Initial commit

This commit is contained in:
satire6 2020-09-11 12:58:04 -04:00
commit 0e7bfc1fe2
2837 changed files with 897984 additions and 0 deletions

3
README.txt Normal file
View file

@ -0,0 +1,3 @@
Toontown Online is a MMORPG created by Disney Interactive, shut down in 2013.
This is a collection of various source code for the game.

5
otp/.cvsignore Normal file
View file

@ -0,0 +1,5 @@
.cvsignore
__init__.py
Makefile
pp.dep
built

11
otp/.project Normal file
View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>otp</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
</buildSpec>
<natures>
</natures>
</projectDescription>

63
otp/Package.pp Normal file
View file

@ -0,0 +1,63 @@
//
// Package.pp
//
// This file defines certain configuration variables that are to be
// written into the various make scripts. It is processed by ppremake
// (along with the Sources.pp files in each of the various
// directories) to generate build scripts appropriate to each
// environment.
//
// This is the package-specific file, which should be at the top of
// every source hierarchy. It generally gets the ball rolling, and is
// responsible for explicitly including all of the relevent Config.pp
// files.
// What is the name and version of this source tree?
#if $[eq $[PACKAGE],]
#define PACKAGE otp
#define VERSION 0.80
#endif
// Where should we find the DIRECT source directory?
#if $[DIRECT_SOURCE]
#define DIRECT_SOURCE $[unixfilename $[DIRECT_SOURCE]]
#elif $[or $[CTPROJS],$[DIRECT]]
// If we are presently attached, use the environment variable.
#define DIRECT_SOURCE $[unixfilename $[DIRECT]]
#if $[eq $[DIRECT],]
#error You seem to be attached to some trees, but not DIRECT!
#endif
#else
// Otherwise, if we are not attached, we guess that the source is a
// sibling directory to this source root.
#define DIRECT_SOURCE $[standardize $[TOPDIR]/../direct]
#endif
// Where should we install OTP?
#if $[OTP_INSTALL]
#define OTP_INSTALL $[unixfilename $[OTP_INSTALL]]
#elif $[CTPROJS]
#set OTP $[unixfilename $[OTP]]
#define OTP_INSTALL $[OTP]/built
#if $[eq $[OTP],]
#error You seem to be attached to some trees, but not OTP!
#endif
#else
#defer OTP_INSTALL $[unixfilename $[INSTALL_DIR]]
#endif
// Also get the DIRECT Package file and everything that includes.
#if $[not $[isfile $[DIRECT_SOURCE]/Package.pp]]
#printvar DIRECT_SOURCE
#error DIRECT source directory not found from otp! Are you attached properly?
#endif
#include $[DIRECT_SOURCE]/Package.pp
// Define the inter-tree dependencies.
#define NEEDS_TREES direct $[NEEDS_TREES]
#define DEPENDABLE_HEADER_DIRS $[DEPENDABLE_HEADER_DIRS] $[DIRECT_INSTALL]/include

10
otp/Sources.pp Normal file
View file

@ -0,0 +1,10 @@
// This is the toplevel directory for a package.
#define DIR_TYPE toplevel
#define REQUIRED_TREES dtool panda direct
#define EXTRA_DIST \
Sources.pp Config.pp Package.pp
#define PYTHON_PACKAGE 1

7
otp/metalibs/Sources.pp Normal file
View file

@ -0,0 +1,7 @@
// This is a group directory: a directory level above a number of
// source subdirectories.
#define DIR_TYPE group
// The metalibs directory always depends on the src directory.
#define DEPENDS src

View file

@ -0,0 +1,2 @@
.cvsignore
Makefile

View file

@ -0,0 +1,33 @@
// DIR_TYPE "metalib" indicates we are building a shared library that
// consists mostly of references to other shared libraries. Under
// Windows, this directly produces a DLL (as opposed to the regular
// src libraries, which don't produce anything but a pile of OBJ files
// under Windows).
#define DIR_TYPE metalib
#define BUILDING_DLL BUILDING_OTP
#define COMPONENT_LIBS \
otpbase settings nametag movement secure navigation
#define OTHER_LIBS direct panda pandaexpress dtoolconfig dtool \
express:c prc:c event:c pgraph:c pgraphnodes:c linmath:c gobj:c lerp:c \
char:c putil:c mathutil:c downloader:c mathutil:c chan:c \
pandabase:c recorder:c grutil:c chan:c collide:c device:c \
dgraph:c display:c gsgbase:c parametrics:c text:c pnmimage:c \
dtoolutil:c interrogatedb:c interval:c dtoolbase:c \
dconfig:c pipeline:c pstatclient:c cull:c pnmimagetypes:c \
tform:c audio:c pgui:c directbase:c dcparser:c showbase:c \
deadrec:c distributed:c motiontrail:c movies:c \
$[if $[HAVE_NET],net:c] $[if $[WANT_NATIVE_NET],nativenet:c]
#if $[HAVE_FREETYPE]
#define OTHER_LIBS $[OTHER_LIBS] pnmtext:c
#endif
#begin metalib_target
#define TARGET otp
#define SOURCES otp.cxx
#end metalib_target

9
otp/metalibs/otp/otp.cxx Normal file
View file

@ -0,0 +1,9 @@
// Filename: otp.cxx
// Created by: drose (18May00)
//
// This is a dummy file whose sole purpose is to give the compiler
// something to compile when making libtoontown.so in NO_DEFER mode,
// which generates an empty library that itself links with all the
// other shared libraries that make up libtoontown.

2
otp/src/.cvsignore Normal file
View file

@ -0,0 +1,2 @@
.cvsignore
Makefile

4
otp/src/Sources.pp Normal file
View file

@ -0,0 +1,4 @@
// This is a group directory: a directory level above a number of
// source subdirectories.
#define DIR_TYPE group

View file

@ -0,0 +1,12 @@
[Add.Code]
DisneyOnlineGames.ocx=DisneyOnlineGames.ocx
DisneyOnlineGames.inf=DisneyOnlineGames.inf
[DisneyOnlineGames.ocx]
file=thiscab
clsid={3DCEC959-378A-4922-AD7E-FD5C925D927F}
RegisterServer=yes
FileVersion=7,6,6,1549
[DisneyOnlineGames.inf]
file=thiscab

View file

@ -0,0 +1,3 @@
signcode -spc \\sesrccdfile01\Verisign_Credentials\WaltDisneyCompany\mycredentials.spc -v \\sesrccdfile01\Verisign_Credentials\WaltDisneyCompany\myprivatekey.pvk -n "Disney Online Games ActiveX Control" -t http://timestamp.verisign.com/scripts/timstamp.dll DisneyOnlineGames.ocx
cabarc -s 6144 n DisneyOnlineGames.cab DisneyOnlineGames.ocx DisneyOnlineGames.inf
signcode -spc \\sesrccdfile01\Verisign_Credentials\WaltDisneyCompany\mycredentials.spc -v \\sesrccdfile01\Verisign_Credentials\WaltDisneyCompany\myprivatekey.pvk -n "Disney Online Games ActiveX Control" -t http://timestamp.verisign.com/scripts/timstamp.dll DisneyOnlineGames.cab

Binary file not shown.

View file

@ -0,0 +1,21 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DisneyOnlineGames", "DisneyOnlineGames.Visual Studio 2003.vcproj", "{230D7CA9-17C1-4FF6-92E0-E620C7314D77}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Debug.ActiveCfg = Debug|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Debug.Build.0 = Debug|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Release.ActiveCfg = Release|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,235 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="DisneyOnlineGames"
ProjectGUID="{230D7CA9-17C1-4FF6-92E0-E620C7314D77}"
Keyword="MFCActiveXProj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
UseOfMFC="1"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
TreatWChar_tAsBuiltInType="TRUE"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/DisneyOnlineGames.ocx"
LinkIncremental="1"
ModuleDefinitionFile=".\DisneyOnlineGames.def"
GenerateDebugInformation="TRUE"
AssemblyDebug="1"
SubSystem="2"
ImportLibrary="$(OutDir)/DisneyOnlineGames.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="FALSE"
TypeLibraryName="$(IntDir)/$(ProjectName).tlb"
HeaderFileName="$(ProjectName)idl.h"/>
<Tool
Name="VCPostBuildEventTool"
Description="Performing registration"
CommandLine="regsvr32 /s /c &quot;$(TargetPath)&quot;"
ExcludedFromBuild="TRUE"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="..\_copy-OCX_to---built---when_ready_to_have_signed"
IntermediateDirectory="Release"
ConfigurationType="2"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="TRUE">
<Tool
Name="VCCLCompilerTool"
GlobalOptimizations="TRUE"
OptimizeForWindowsApplication="TRUE"
PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL"
StringPooling="TRUE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="TRUE"
TreatWChar_tAsBuiltInType="TRUE"
UsePrecompiledHeader="3"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/DisneyOnlineGames.ocx"
LinkIncremental="1"
ModuleDefinitionFile=".\DisneyOnlineGames.def"
GenerateDebugInformation="FALSE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
OptimizeForWindows98="1"
ImportLibrary="$(IntDir)/DisneyOnlineGames.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="FALSE"
TypeLibraryName="$(IntDir)/$(ProjectName).tlb"
HeaderFileName="$(ProjectName)idl.h"/>
<Tool
Name="VCPostBuildEventTool"
Description="Performing registration"
CommandLine="regsvr32 /s /c &quot;$(TargetPath)&quot;"
ExcludedFromBuild="TRUE"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\DisneyOnlineGames.cpp">
</File>
<File
RelativePath=".\DisneyOnlineGames.def">
</File>
<File
RelativePath=".\DisneyOnlineGames.idl">
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.cpp">
</File>
<File
RelativePath=".\DisneyOnlineGamesPropPage.cpp">
</File>
<File
RelativePath=".\EnvBlock.cpp">
</File>
<File
RelativePath=".\RunPiratesOnline.cpp">
</File>
<File
RelativePath=".\stdafx.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\TopLevelWindowIterator.cpp">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\DisneyOnlineGames.h">
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.h">
</File>
<File
RelativePath=".\DisneyOnlineGamesPropPage.h">
</File>
<File
RelativePath=".\EnvBlock.h">
</File>
<File
RelativePath=".\Resource.h">
</File>
<File
RelativePath=".\RunPiratesOnline.h">
</File>
<File
RelativePath=".\stdafx.h">
</File>
<File
RelativePath=".\TopLevelWindowIterator.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
<File
RelativePath=".\DisneyOnlineGames.rc">
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.bmp">
</File>
</Filter>
</Files>
<Globals>
<Global
Name="RESOURCE_FILE"
Value="DisneyOnlineGames.rc"/>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DisneyOnlineGames", "DisneyOnlineGames.Visual Studio 2005.vcproj", "{230D7CA9-17C1-4FF6-92E0-E620C7314D77}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Debug|Win32.ActiveCfg = Debug|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Debug|Win32.Build.0 = Debug|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Release|Win32.ActiveCfg = Release|Win32
{230D7CA9-17C1-4FF6-92E0-E620C7314D77}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,327 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="DisneyOnlineGames"
ProjectGUID="{230D7CA9-17C1-4FF6-92E0-E620C7314D77}"
RootNamespace="DisneyOnlineGames"
Keyword="MFCActiveXProj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="_DEBUG"
MkTypLibCompatible="false"
TypeLibraryName="$(IntDir)/$(ProjectName).tlb"
HeaderFileName="$(ProjectName)idl.h"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
TreatWChar_tAsBuiltInType="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="_DEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wininet.lib"
OutputFile="$(OutDir)/DisneyOnlineGames.ocx"
LinkIncremental="1"
ModuleDefinitionFile=".\DisneyOnlineGames.def"
GenerateDebugInformation="true"
AssemblyDebug="1"
SubSystem="2"
ImportLibrary="$(OutDir)/DisneyOnlineGames.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
Description="Performing registration"
CommandLine="regsvr32 /s /c &quot;$(TargetPath)&quot;"
ExcludedFromBuild="true"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="..\_copy-OCX_to---built---when_ready_to_have_signed"
IntermediateDirectory="Release"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
PreprocessorDefinitions="NDEBUG"
MkTypLibCompatible="false"
TypeLibraryName="$(IntDir)/$(ProjectName).tlb"
HeaderFileName="$(ProjectName)idl.h"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
TreatWChar_tAsBuiltInType="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
PreprocessorDefinitions="NDEBUG"
Culture="1033"
AdditionalIncludeDirectories="$(IntDir)"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wininet.lib"
OutputFile="$(OutDir)/DisneyOnlineGames.ocx"
LinkIncremental="1"
ModuleDefinitionFile=".\DisneyOnlineGames.def"
GenerateDebugInformation="false"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
OptimizeForWindows98="1"
ImportLibrary="$(IntDir)/DisneyOnlineGames.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
Description="Performing registration"
CommandLine="regsvr32 /s /c &quot;$(TargetPath)&quot;"
ExcludedFromBuild="true"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\DisneyOnlineGames.cpp"
>
</File>
<File
RelativePath=".\DisneyOnlineGames.def"
>
</File>
<File
RelativePath=".\DisneyOnlineGames.idl"
>
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.cpp"
>
</File>
<File
RelativePath=".\DisneyOnlineGamesPropPage.cpp"
>
</File>
<File
RelativePath=".\EnvBlock.cpp"
>
</File>
<File
RelativePath=".\RunPiratesOnline.cpp"
>
</File>
<File
RelativePath=".\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\TopLevelWindowIterator.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\DisneyOnlineGames.h"
>
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.h"
>
</File>
<File
RelativePath=".\DisneyOnlineGamesPropPage.h"
>
</File>
<File
RelativePath=".\EnvBlock.h"
>
</File>
<File
RelativePath=".\Resource.h"
>
</File>
<File
RelativePath=".\RunPiratesOnline.h"
>
</File>
<File
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath=".\TopLevelWindowIterator.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
<File
RelativePath=".\DisneyOnlineGames.rc"
>
</File>
<File
RelativePath=".\DisneyOnlineGamesCtrl.bmp"
>
</File>
</Filter>
</Files>
<Globals>
<Global
Name="RESOURCE_FILE"
Value="DisneyOnlineGames.rc"
/>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,201 @@
#include "stdafx.h"
#include "DisneyOnlineGames.h"
#include "comcat.h"
#include "strsafe.h"
#include "objsafe.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CLSID_SafeItem - Necessary for safe ActiveX control
// Taken from IMPLEMENT_OLECREATE_EX function in DisneyOnlineGamesCtrl.cpp
const CATID CLSID_SafeItem =
{ 0x3dcec959, 0x378a, 0x4922,{ 0xad, 0x7e, 0xfd, 0x5c, 0x92, 0x5d, 0x92, 0x7f}};
HRESULT CreateComponentCategory(CATID catid, WCHAR *catDescription)
{
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr))
return hr;
// Make sure the HKCR\Component Categories\{..catid...}
// key is registered.
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
size_t len;
// Make sure the provided description is not too long.
// Only copy the first 127 characters if it is.
// The second parameter of StringCchLength is the maximum
// number of characters that may be read into catDescription.
// There must be room for a NULL-terminator. The third parameter
// contains the number of characters excluding the NULL-terminator.
hr = StringCchLengthW(catDescription, STRSAFE_MAX_CCH, &len);
if (SUCCEEDED(hr))
{
if (len>127)
{
len = 127;
}
}
else
{
// TODO: Write an error handler;
}
// The second parameter of StringCchCopy is 128 because you need
// room for a NULL-terminator.
hr = StringCchCopyW(catinfo.szDescription, len + 1, catDescription);
// Make sure the description is null terminated.
catinfo.szDescription[len + 1] = '\0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
// HRESULT RegisterCLSIDInCategory -
// Register your component categories information
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Register this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
// HRESULT UnRegisterCLSIDInCategory - Remove entries from the registry
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister *pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr,
NULL, CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Unregister this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
CDisneyOnlineGamesApp theApp;
const GUID CDECL BASED_CODE _tlid =
{ 0x5F6C8F0A, 0x6FE5, 0x4546, { 0x82, 0xF1, 0x9B, 0x50, 0x37, 0x3A, 0x8E, 0xBD } };
const WORD _wVerMajor = 3;
const WORD _wVerMinor = 1;
BOOL CDisneyOnlineGamesApp::InitInstance()
// DLL initialization
{
BOOL bInit = COleControlModule::InitInstance();
if (bInit)
{
// TODO: Add your own module initialization code here.
}
return bInit;
}
int CDisneyOnlineGamesApp::ExitInstance()
// DLL termination
{
// TODO: Add your own module termination code here.
return COleControlModule::ExitInstance();
}
STDAPI DllRegisterServer(void)
// Adds entries to the system registry
{
HRESULT hr; // HResult used by Safety Functions
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
return ResultFromScode(SELFREG_E_CLASS);
// Mark the control as safe for initializing.
hr = CreateComponentCategory(CATID_SafeForInitializing,
L"Controls safely initializable from persistent data!");
if (FAILED(hr))
return hr;
hr = RegisterCLSIDInCategory(CLSID_SafeItem,
CATID_SafeForInitializing);
if (FAILED(hr))
return hr;
// Mark the control as safe for scripting.
hr = CreateComponentCategory(CATID_SafeForScripting,
L"Controls safely scriptable!");
if (FAILED(hr))
return hr;
hr = RegisterCLSIDInCategory(CLSID_SafeItem,
CATID_SafeForScripting);
if (FAILED(hr))
return hr;
return NOERROR;
}
STDAPI DllUnregisterServer(void)
// Removes entries from the system registry
{
HRESULT hr; // HResult used by Safety Functions
AFX_MANAGE_STATE(_afxModuleAddrThis);
if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor))
return ResultFromScode(SELFREG_E_TYPELIB);
if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
return ResultFromScode(SELFREG_E_CLASS);
// Remove entries from the registry.
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem,
CATID_SafeForInitializing);
if (FAILED(hr))
return hr;
hr=UnRegisterCLSIDInCategory(CLSID_SafeItem,
CATID_SafeForScripting);
if (FAILED(hr))
return hr;
return NOERROR;
}

View file

@ -0,0 +1,9 @@
; DisneyOnlineGames.def : Declares the module parameters.
LIBRARY "DisneyOnlineGames.OCX"
EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE

View file

@ -0,0 +1,20 @@
#pragma once
#if !defined( __AFXCTL_H__ )
#error "include 'afxctl.h' before including this file"
#endif
#include "resource.h" // main symbols
class CDisneyOnlineGamesApp : public COleControlModule
{
public:
BOOL InitInstance();
int ExitInstance();
};
extern const GUID CDECL _tlid;
extern const WORD _wVerMajor;
extern const WORD _wVerMinor;

View file

@ -0,0 +1,55 @@
// DisneyOnlineGames.idl : type library source for ActiveX Control project.
// This file will be processed by the MIDL compiler tool to
// produce the type library (DisneyOnlineGames.tlb) that will become a resource in
// DisneyOnlineGames.ocx.
#include <olectl.h>
#include <idispids.h>
[ uuid(5F6C8F0A-6FE5-4546-82F1-9B50373A8EBD), version(1.0),
helpfile("DisneyOnlineGames.hlp"),
helpstring("Disney Online Games ActiveX Control module"),
control ]
library DisneyOnlineGamesLib
{
importlib(STDOLE_TLB);
// Primary dispatch interface for CDisneyOnlineGamesCtrl
[ uuid(33BDF503-F6F7-456C-B3C9-F74F294C8EB7),
helpstring("Dispatch interface for Disney Online Games Control")]
dispinterface _DDisneyOnlineGames
{
properties:
[id(2), helpstring("property ModeId")] BSTR ModeId;
[id(9) , helpstring("property ResponseCode")] ULONG ResponseCode;
[id(10) , helpstring("property Token")] BSTR Token;
methods:
[id(5), helpstring("method runPiratesOnline")] void runPiratesOnline(void);
};
// Event dispatch interface for CDisneyOnlineGamesCtrl
[ uuid(CAC95DCF-C37B-4173-901A-ED2D6EDC5177),
helpstring("Event interface for Disney Online Games Control") ]
dispinterface _DDisneyOnlineGamesEvents
{
properties:
// Event interface has no properties
methods:
[id(1)] void onRunPiratesOnlineComplete(void);
};
// Class information for CDisneyOnlineGamesCtrl
[ uuid(3DCEC959-378A-4922-AD7E-FD5C925D927F),
helpstring("Disney Online Games Control"), control ]
coclass DisneyOnlineGames
{
[default] dispinterface _DDisneyOnlineGames;
[default, source] dispinterface _DDisneyOnlineGamesEvents;
};
};

View file

@ -0,0 +1,159 @@
// 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
"1 TYPELIB ""DisneyOnlineGames.tlb""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 7,6,6,1549
PRODUCTVERSION 3,0,1,5
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904e4"
BEGIN
VALUE "CompanyName", "Walt Disney Co."
VALUE "FileDescription", "Disney Online Games ActiveX Control"
VALUE "FileVersion", "7, 6, 6, 1549"
VALUE "InternalName", "DisneyOnlineGames.ocx"
VALUE "LegalCopyright", "Copyright © 2007 Walt Disney Co."
VALUE "OriginalFilename", "DisneyOnlineGames.ocx"
VALUE "ProductName", "DisneyOnlineGames"
VALUE "ProductVersion", "3, 0, 1, 5"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDB_DISNEYONLINEGAMES BITMAP "DisneyOnlineGamesCtrl.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PROPPAGE_DISNEYONLINEGAMES DIALOG 0, 0, 250, 62
STYLE DS_SETFONT | WS_CHILD
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "TODO: Place controls to manipulate properties of DisneyOnlineGames Control on this dialog.",
IDC_STATIC,7,25,229,16
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PROPPAGE_DISNEYONLINEGAMES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 243
TOPMARGIN, 7
BOTTOMMARGIN, 55
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_DISNEYONLINEGAMES "Disney Online Games ActiveX Control"
IDS_DISNEYONLINEGAMES_PPG "Disney Online Games ActiveX Property Page"
END
STRINGTABLE
BEGIN
IDS_DISNEYONLINEGAMES_PPG_CAPTION "General"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
1 TYPELIB "DisneyOnlineGames.tlb"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

View file

@ -0,0 +1,236 @@
#include "stdafx.h"
#include "DisneyOnlineGames.h"
#include "DisneyOnlineGamesCtrl.h"
#include "DisneyOnlineGamesPropPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(CDisneyOnlineGamesCtrl, COleControl)
// Message map
BEGIN_MESSAGE_MAP(CDisneyOnlineGamesCtrl, COleControl)
ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()
// Dispatch map
BEGIN_DISPATCH_MAP(CDisneyOnlineGamesCtrl, COleControl)
DISP_PROPERTY_NOTIFY_ID(CDisneyOnlineGamesCtrl, "ModeId", dispidModeId, m_ModeId, OnModeIdChanged, VT_BSTR)
DISP_FUNCTION_ID(CDisneyOnlineGamesCtrl, "runPiratesOnline", dispidrunPiratesOnline, exportedmethodrunPiratesOnline, VT_EMPTY, VTS_NONE)
DISP_PROPERTY_NOTIFY_ID(CDisneyOnlineGamesCtrl, "ResponseCode", dispidResponseCode, m_ResponseCode, OnResponseCodeChanged, VT_UI4)
DISP_PROPERTY_NOTIFY_ID(CDisneyOnlineGamesCtrl, "Token", dispidToken, m_Token, OnTokenChanged, VT_BSTR)
END_DISPATCH_MAP()
// Event map
BEGIN_EVENT_MAP(CDisneyOnlineGamesCtrl, COleControl)
EVENT_CUSTOM_ID("onRunPiratesOnlineComplete", eventidonRunPiratesOnlineComplete, Fire_onRunPiratesOnlineComplete, VTS_NONE)
END_EVENT_MAP()
// Property pages
// TODO: Add more property pages as needed. Remember to increase the count!
BEGIN_PROPPAGEIDS(CDisneyOnlineGamesCtrl, 1)
PROPPAGEID(CDisneyOnlineGamesPropPage::guid)
END_PROPPAGEIDS(CDisneyOnlineGamesCtrl)
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CDisneyOnlineGamesCtrl, "DISNEYONLINEGAMES.DisneyOnlineGamesCtrl.1",
0x3dcec959, 0x378a, 0x4922, 0xad, 0x7e, 0xfd, 0x5c, 0x92, 0x5d, 0x92, 0x7f)
// Type library ID and version
IMPLEMENT_OLETYPELIB(CDisneyOnlineGamesCtrl, _tlid, _wVerMajor, _wVerMinor)
// Interface IDs
const IID BASED_CODE IID_DDisneyOnlineGames =
{ 0x33BDF503, 0xF6F7, 0x456C, { 0xB3, 0xC9, 0xF7, 0x4F, 0x29, 0x4C, 0x8E, 0xB7 } };
const IID BASED_CODE IID_DDisneyOnlineGamesEvents =
{ 0xCAC95DCF, 0xC37B, 0x4173, { 0x90, 0x1A, 0xED, 0x2D, 0x6E, 0xDC, 0x51, 0x77 } };
// Control type information
static const DWORD BASED_CODE _dwDisneyOnlineGamesOleMisc =
OLEMISC_ALWAYSRUN |
OLEMISC_SETCLIENTSITEFIRST |
OLEMISC_INSIDEOUT |
OLEMISC_CANTLINKINSIDE |
OLEMISC_ACTIVATEWHENVISIBLE
;
IMPLEMENT_OLECTLTYPE(CDisneyOnlineGamesCtrl, IDS_DISNEYONLINEGAMES, _dwDisneyOnlineGamesOleMisc)
// CDisneyOnlineGamesCtrl::CDisneyOnlineGamesCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CDisneyOnlineGamesCtrl
BOOL CDisneyOnlineGamesCtrl::CDisneyOnlineGamesCtrlFactory::UpdateRegistry(BOOL bRegister)
{
// TODO: Verify that your control follows apartment-model threading rules.
// Refer to MFC TechNote 64 for more information.
// If your control does not conform to the apartment-model rules, then
// you must modify the code below, changing the 6th parameter from
// afxRegInsertable | afxRegApartmentThreading to afxRegInsertable.
if (bRegister)
return AfxOleRegisterControlClass(
AfxGetInstanceHandle(),
m_clsid,
m_lpszProgID,
IDS_DISNEYONLINEGAMES,
IDB_DISNEYONLINEGAMES,
afxRegInsertable | afxRegApartmentThreading | afxRegFreeThreading,
_dwDisneyOnlineGamesOleMisc,
_tlid,
_wVerMajor,
_wVerMinor);
else
return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}
// CDisneyOnlineGamesCtrl::CDisneyOnlineGamesCtrl - Constructor
CDisneyOnlineGamesCtrl::CDisneyOnlineGamesCtrl()
{
InitializeIIDs(&IID_DDisneyOnlineGames, &IID_DDisneyOnlineGamesEvents);
}
// CDisneyOnlineGamesCtrl::~CDisneyOnlineGamesCtrl - Destructor
CDisneyOnlineGamesCtrl::~CDisneyOnlineGamesCtrl()
{
// TODO: Cleanup your control's instance data here.
}
// CDisneyOnlineGamesCtrl::OnDraw - Drawing function
void CDisneyOnlineGamesCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
if (!pdc)
return;
}
// CDisneyOnlineGamesCtrl::DoPropExchange - Persistence support
void CDisneyOnlineGamesCtrl::DoPropExchange(CPropExchange* pPX)
{
ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
COleControl::DoPropExchange(pPX);
// TODO: Call PX_ functions for each persistent custom property.
}
// CDisneyOnlineGamesCtrl::GetControlFlags -
// Flags to customize MFC's implementation of ActiveX controls.
//
DWORD CDisneyOnlineGamesCtrl::GetControlFlags()
{
DWORD dwFlags = COleControl::GetControlFlags();
return dwFlags;
}
// CDisneyOnlineGamesCtrl::OnResetState - Reset control to default state
void CDisneyOnlineGamesCtrl::OnResetState()
{
COleControl::OnResetState(); // Resets defaults found in DoPropExchange
// TODO: Reset any other control state here.
}
// CDisneyOnlineGamesCtrl message handlers
void CDisneyOnlineGamesCtrl::OnModeIdChanged(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your property handler code here
SetModifiedFlag();
}
void CDisneyOnlineGamesCtrl::exportedmethodrunPiratesOnline (void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
#if defined(_DEBUG_TOKEN_VALUE_)
{
// If the request to obtain the path to temporary directory failed
char szTempPath [MAX_PATH];
if (GetTempPath (MAX_PATH, szTempPath))
{
// If the request to obtain a unique temporary filename failed
char szInstallerFullPathname [MAX_PATH];
if (GetTempFileName (szTempPath, NULL, 0, szInstallerFullPathname))
{
// If the temporary file was not successfully opened for writing
HANDLE hFile;
if (INVALID_HANDLE_VALUE != (hFile = CreateFile (
szInstallerFullPathname,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)))
{
char szPrefix [] = "m_Token=\"";
char szSuffix [] = "\"";
char * pszBuf = (char *)malloc (lstrlen (szPrefix) + lstrlen (m_Token) + lstrlen (szSuffix) + 1);
strcpy (pszBuf, szPrefix);
strcat (pszBuf, m_Token);
strcat (pszBuf, szSuffix);
//
DWORD dwNumberOfBytesWritten;
WriteFile (hFile, pszBuf, lstrlen (pszBuf), &dwNumberOfBytesWritten, NULL);
//
CloseHandle (hFile);
}
}
}
}
#endif
CRunPiratesOnline * pRunPiratesOnline = new CRunPiratesOnline ();
m_ResponseCode = pRunPiratesOnline->Run (atoi (m_ModeId), m_Token);
delete pRunPiratesOnline;
// If our attempt to run Pirates Online was successful
if (RESPONSE_CODE__SUCCESS == m_ResponseCode)
{
CTopLevelWindowIterator itlw (GetCurrentProcessId ());
for (HWND hWndTopLevelWindow = itlw.First(); hWndTopLevelWindow; hWndTopLevelWindow = itlw.Next())
{
// Minimize the top level window that was created by this process
::ShowWindow (hWndTopLevelWindow, SW_MINIMIZE);
}
}
// Fire response to webpage
Fire_onRunPiratesOnlineComplete ();
}
void CDisneyOnlineGamesCtrl::OnResponseCodeChanged(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your property handler code here
SetModifiedFlag();
}
void CDisneyOnlineGamesCtrl::OnTokenChanged(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your property handler code here
SetModifiedFlag();
}

View file

@ -0,0 +1,58 @@
#pragma once
class CDisneyOnlineGamesCtrl : public COleControl
{
DECLARE_DYNCREATE(CDisneyOnlineGamesCtrl)
// Constructor
public:
CDisneyOnlineGamesCtrl();
// Overrides
public:
virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
virtual void DoPropExchange(CPropExchange* pPX);
virtual void OnResetState();
virtual DWORD GetControlFlags();
// Implementation
protected:
~CDisneyOnlineGamesCtrl();
DECLARE_OLECREATE_EX(CDisneyOnlineGamesCtrl) // Class factory and guid
DECLARE_OLETYPELIB(CDisneyOnlineGamesCtrl) // GetTypeInfo
DECLARE_PROPPAGEIDS(CDisneyOnlineGamesCtrl) // Property page IDs
DECLARE_OLECTLTYPE(CDisneyOnlineGamesCtrl) // Type name and misc status
// Message maps
DECLARE_MESSAGE_MAP()
// Dispatch maps
DECLARE_DISPATCH_MAP()
// Event maps
DECLARE_EVENT_MAP()
// Dispatch and event IDs
public:
enum {
dispidToken = 10,
eventidonRunPiratesOnlineComplete = 1L,
dispidResponseCode = 9,
dispidrunPiratesOnline = 5L,
dispidModeId = 2,
};
protected:
void OnModeIdChanged(void);
CString m_ModeId;
void exportedmethodrunPiratesOnline(void);
void OnResponseCodeChanged(void);
ULONG m_ResponseCode;
void OnTokenChanged(void);
CString m_Token;
void Fire_onRunPiratesOnlineComplete(void)
{
FireEvent(eventidonRunPiratesOnlineComplete, EVENT_PARAM(VTS_NONE));
}
};

View file

@ -0,0 +1,60 @@
#include "stdafx.h"
#include "DisneyOnlineGames.h"
#include "DisneyOnlineGamesPropPage.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(CDisneyOnlineGamesPropPage, COlePropertyPage)
// Message map
BEGIN_MESSAGE_MAP(CDisneyOnlineGamesPropPage, COlePropertyPage)
END_MESSAGE_MAP()
// Initialize class factory and guid
IMPLEMENT_OLECREATE_EX(CDisneyOnlineGamesPropPage, "DISNEYONLINEGAMES.DisneyOnlineGamesPropPage.1",
0xe314aa7, 0x9a00, 0x4db3, 0xb0, 0x23, 0x7a, 0xda, 0x8d, 0xdf, 0x7d, 0x26)
// CDisneyOnlineGamesPropPage::CDisneyOnlineGamesPropPageFactory::UpdateRegistry -
// Adds or removes system registry entries for CDisneyOnlineGamesPropPage
BOOL CDisneyOnlineGamesPropPage::CDisneyOnlineGamesPropPageFactory::UpdateRegistry(BOOL bRegister)
{
if (bRegister)
return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),
m_clsid, IDS_DISNEYONLINEGAMES_PPG);
else
return AfxOleUnregisterClass(m_clsid, NULL);
}
// CDisneyOnlineGamesPropPage::CDisneyOnlineGamesPropPage - Constructor
CDisneyOnlineGamesPropPage::CDisneyOnlineGamesPropPage() :
COlePropertyPage(IDD, IDS_DISNEYONLINEGAMES_PPG_CAPTION)
{
}
// CDisneyOnlineGamesPropPage::DoDataExchange - Moves data between page and properties
void CDisneyOnlineGamesPropPage::DoDataExchange(CDataExchange* pDX)
{
DDP_PostProcessing(pDX);
}
// CDisneyOnlineGamesPropPage message handlers

View file

@ -0,0 +1,23 @@
#pragma once
class CDisneyOnlineGamesPropPage : public COlePropertyPage
{
DECLARE_DYNCREATE(CDisneyOnlineGamesPropPage)
DECLARE_OLECREATE_EX(CDisneyOnlineGamesPropPage)
// Constructor
public:
CDisneyOnlineGamesPropPage();
// Dialog Data
enum { IDD = IDD_PROPPAGE_DISNEYONLINEGAMES };
// Implementation
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Message maps
protected:
DECLARE_MESSAGE_MAP()
};

View file

@ -0,0 +1,93 @@
/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
/* link this file in with the server and any clients */
/* File created by MIDL compiler version 6.00.0361 */
/* at Wed Jun 06 15:59:25 2007
*/
/* Compiler settings for .\DisneyOnlineGames.idl:
Oicf, W1, Zp8, env=Win32 (32b run)
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
//@@MIDL_FILE_HEADING( )
#if !defined(_M_IA64) && !defined(_M_AMD64)
#pragma warning( disable: 4049 ) /* more than 64k source lines */
#ifdef __cplusplus
extern "C"{
#endif
#include <rpc.h>
#include <rpcndr.h>
#ifdef _MIDL_USE_GUIDDEF_
#ifndef INITGUID
#define INITGUID
#include <guiddef.h>
#undef INITGUID
#else
#include <guiddef.h>
#endif
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
#else // !_MIDL_USE_GUIDDEF_
#ifndef __IID_DEFINED__
#define __IID_DEFINED__
typedef struct _IID
{
unsigned long x;
unsigned short s1;
unsigned short s2;
unsigned char c[8];
} IID;
#endif // __IID_DEFINED__
#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED
#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
#endif !_MIDL_USE_GUIDDEF_
MIDL_DEFINE_GUID(IID, LIBID_DisneyOnlineGamesLib,0x5F6C8F0A,0x6FE5,0x4546,0x82,0xF1,0x9B,0x50,0x37,0x3A,0x8E,0xBD);
MIDL_DEFINE_GUID(IID, DIID__DDisneyOnlineGames,0x33BDF503,0xF6F7,0x456C,0xB3,0xC9,0xF7,0x4F,0x29,0x4C,0x8E,0xB7);
MIDL_DEFINE_GUID(IID, DIID__DDisneyOnlineGamesEvents,0xCAC95DCF,0xC37B,0x4173,0x90,0x1A,0xED,0x2D,0x6E,0xDC,0x51,0x77);
MIDL_DEFINE_GUID(CLSID, CLSID_DisneyOnlineGames,0x3DCEC959,0x378A,0x4922,0xAD,0x7E,0xFD,0x5C,0x92,0x5D,0x92,0x7F);
#undef MIDL_DEFINE_GUID
#ifdef __cplusplus
}
#endif
#endif /* !defined(_M_IA64) && !defined(_M_AMD64)*/

View file

@ -0,0 +1,316 @@
/* this ALWAYS GENERATED file contains the definitions for the interfaces */
/* File created by MIDL compiler version 6.00.0361 */
/* at Wed Jun 06 15:59:25 2007
*/
/* Compiler settings for .\DisneyOnlineGames.idl:
Oicf, W1, Zp8, env=Win32 (32b run)
protocol : dce , ms_ext, c_ext, robust
error checks: allocation ref bounds_check enum stub_data
VC __declspec() decoration level:
__declspec(uuid()), __declspec(selectany), __declspec(novtable)
DECLSPEC_UUID(), MIDL_INTERFACE()
*/
//@@MIDL_FILE_HEADING( )
#pragma warning( disable: 4049 ) /* more than 64k source lines */
/* verify that the <rpcndr.h> version is high enough to compile this file*/
#ifndef __REQUIRED_RPCNDR_H_VERSION__
#define __REQUIRED_RPCNDR_H_VERSION__ 475
#endif
#include "rpc.h"
#include "rpcndr.h"
#ifndef __RPCNDR_H_VERSION__
#error this stub requires an updated version of <rpcndr.h>
#endif // __RPCNDR_H_VERSION__
#ifndef __DisneyOnlineGamesidl_h__
#define __DisneyOnlineGamesidl_h__
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
/* Forward Declarations */
#ifndef ___DDisneyOnlineGames_FWD_DEFINED__
#define ___DDisneyOnlineGames_FWD_DEFINED__
typedef interface _DDisneyOnlineGames _DDisneyOnlineGames;
#endif /* ___DDisneyOnlineGames_FWD_DEFINED__ */
#ifndef ___DDisneyOnlineGamesEvents_FWD_DEFINED__
#define ___DDisneyOnlineGamesEvents_FWD_DEFINED__
typedef interface _DDisneyOnlineGamesEvents _DDisneyOnlineGamesEvents;
#endif /* ___DDisneyOnlineGamesEvents_FWD_DEFINED__ */
#ifndef __DisneyOnlineGames_FWD_DEFINED__
#define __DisneyOnlineGames_FWD_DEFINED__
#ifdef __cplusplus
typedef class DisneyOnlineGames DisneyOnlineGames;
#else
typedef struct DisneyOnlineGames DisneyOnlineGames;
#endif /* __cplusplus */
#endif /* __DisneyOnlineGames_FWD_DEFINED__ */
#ifdef __cplusplus
extern "C"{
#endif
void * __RPC_USER MIDL_user_allocate(size_t);
void __RPC_USER MIDL_user_free( void * );
#ifndef __DisneyOnlineGamesLib_LIBRARY_DEFINED__
#define __DisneyOnlineGamesLib_LIBRARY_DEFINED__
/* library DisneyOnlineGamesLib */
/* [control][helpstring][helpfile][version][uuid] */
EXTERN_C const IID LIBID_DisneyOnlineGamesLib;
#ifndef ___DDisneyOnlineGames_DISPINTERFACE_DEFINED__
#define ___DDisneyOnlineGames_DISPINTERFACE_DEFINED__
/* dispinterface _DDisneyOnlineGames */
/* [helpstring][uuid] */
EXTERN_C const IID DIID__DDisneyOnlineGames;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("33BDF503-F6F7-456C-B3C9-F74F294C8EB7")
_DDisneyOnlineGames : public IDispatch
{
};
#else /* C style interface */
typedef struct _DDisneyOnlineGamesVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
_DDisneyOnlineGames * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
_DDisneyOnlineGames * This);
ULONG ( STDMETHODCALLTYPE *Release )(
_DDisneyOnlineGames * This);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )(
_DDisneyOnlineGames * This,
/* [out] */ UINT *pctinfo);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )(
_DDisneyOnlineGames * This,
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo **ppTInfo);
HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )(
_DDisneyOnlineGames * This,
/* [in] */ REFIID riid,
/* [size_is][in] */ LPOLESTR *rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID *rgDispId);
/* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )(
_DDisneyOnlineGames * This,
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr);
END_INTERFACE
} _DDisneyOnlineGamesVtbl;
interface _DDisneyOnlineGames
{
CONST_VTBL struct _DDisneyOnlineGamesVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define _DDisneyOnlineGames_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define _DDisneyOnlineGames_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define _DDisneyOnlineGames_Release(This) \
(This)->lpVtbl -> Release(This)
#define _DDisneyOnlineGames_GetTypeInfoCount(This,pctinfo) \
(This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
#define _DDisneyOnlineGames_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
(This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
#define _DDisneyOnlineGames_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
(This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
#define _DDisneyOnlineGames_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
(This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
#endif /* COBJMACROS */
#endif /* C style interface */
#endif /* ___DDisneyOnlineGames_DISPINTERFACE_DEFINED__ */
#ifndef ___DDisneyOnlineGamesEvents_DISPINTERFACE_DEFINED__
#define ___DDisneyOnlineGamesEvents_DISPINTERFACE_DEFINED__
/* dispinterface _DDisneyOnlineGamesEvents */
/* [helpstring][uuid] */
EXTERN_C const IID DIID__DDisneyOnlineGamesEvents;
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("CAC95DCF-C37B-4173-901A-ED2D6EDC5177")
_DDisneyOnlineGamesEvents : public IDispatch
{
};
#else /* C style interface */
typedef struct _DDisneyOnlineGamesEventsVtbl
{
BEGIN_INTERFACE
HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
_DDisneyOnlineGamesEvents * This,
/* [in] */ REFIID riid,
/* [iid_is][out] */ void **ppvObject);
ULONG ( STDMETHODCALLTYPE *AddRef )(
_DDisneyOnlineGamesEvents * This);
ULONG ( STDMETHODCALLTYPE *Release )(
_DDisneyOnlineGamesEvents * This);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )(
_DDisneyOnlineGamesEvents * This,
/* [out] */ UINT *pctinfo);
HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )(
_DDisneyOnlineGamesEvents * This,
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ ITypeInfo **ppTInfo);
HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )(
_DDisneyOnlineGamesEvents * This,
/* [in] */ REFIID riid,
/* [size_is][in] */ LPOLESTR *rgszNames,
/* [in] */ UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ DISPID *rgDispId);
/* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )(
_DDisneyOnlineGamesEvents * This,
/* [in] */ DISPID dispIdMember,
/* [in] */ REFIID riid,
/* [in] */ LCID lcid,
/* [in] */ WORD wFlags,
/* [out][in] */ DISPPARAMS *pDispParams,
/* [out] */ VARIANT *pVarResult,
/* [out] */ EXCEPINFO *pExcepInfo,
/* [out] */ UINT *puArgErr);
END_INTERFACE
} _DDisneyOnlineGamesEventsVtbl;
interface _DDisneyOnlineGamesEvents
{
CONST_VTBL struct _DDisneyOnlineGamesEventsVtbl *lpVtbl;
};
#ifdef COBJMACROS
#define _DDisneyOnlineGamesEvents_QueryInterface(This,riid,ppvObject) \
(This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
#define _DDisneyOnlineGamesEvents_AddRef(This) \
(This)->lpVtbl -> AddRef(This)
#define _DDisneyOnlineGamesEvents_Release(This) \
(This)->lpVtbl -> Release(This)
#define _DDisneyOnlineGamesEvents_GetTypeInfoCount(This,pctinfo) \
(This)->lpVtbl -> GetTypeInfoCount(This,pctinfo)
#define _DDisneyOnlineGamesEvents_GetTypeInfo(This,iTInfo,lcid,ppTInfo) \
(This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo)
#define _DDisneyOnlineGamesEvents_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) \
(This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)
#define _DDisneyOnlineGamesEvents_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) \
(This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)
#endif /* COBJMACROS */
#endif /* C style interface */
#endif /* ___DDisneyOnlineGamesEvents_DISPINTERFACE_DEFINED__ */
EXTERN_C const CLSID CLSID_DisneyOnlineGames;
#ifdef __cplusplus
class DECLSPEC_UUID("3DCEC959-378A-4922-AD7E-FD5C925D927F")
DisneyOnlineGames;
#endif
#endif /* __DisneyOnlineGamesLib_LIBRARY_DEFINED__ */
/* Additional Prototypes for ALL interfaces */
/* end of Additional Prototypes */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,94 @@
#include "stdafx.h"
void CEnvBlock::insert_env_block_key_value_pair (CString & strEnvForChildProcess,
int * pInsertIdx,
char * lpszVariable)
{
// Insert the next environment block key=value pair, accounting for the following facts:
// 1. There must be a terminating NULL byte ('\0') between each key=value pair
// 2. Two NULL bytes indicate environment block end
//---------------------------------------------------------------------------------------------
// In other words, an environment block consists of a null-terminated block of null-terminated
// strings (meaning there are two null bytes at the end of the block), where each string is of
// the form
// key=value
//---------------------------------------------------------------------------------------------
strEnvForChildProcess.Insert (*pInsertIdx, lpszVariable);
(*pInsertIdx) += (int)strlen (lpszVariable);
(*pInsertIdx)++;
strEnvForChildProcess.GetBufferSetLength (*pInsertIdx);
}
void CEnvBlock::Create (const char * pszEnvKeyToAddToChildProcessEnvBlock,
CString & strEnvForChildProcess)
{
// Set environment key=value pair that the executable will look for
static const char szEnvKeyValuePairSeparator [] = "=";
CString strEnvKeyValuePairToAddToChildProcessEnvBlock;
strEnvKeyValuePairToAddToChildProcessEnvBlock.Format (
"%s%s%s",
pszEnvKeyToAddToChildProcessEnvBlock,
szEnvKeyValuePairSeparator,
m.pszToken);
// Ensure the string to hold the environment block for the child process is empty
strEnvForChildProcess.GetBufferSetLength (0);
// Initilize the child process environment block insert index
int InsertIdx = 0;
// Indicate that the key=value pair that the executable will look for has NOT yet been inserted
bool fAddedEnvKeyToChildProcessEnvBlock = false;
// If a pointer to the environment block for this process was returned
LPVOID lpvEnv;
if (lpvEnv = GetEnvironmentStrings ())
{
// Variable strings are separated by NULL byte, and the block is terminated by a NULL byte
LPTSTR lpszVariable;
for (lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += lstrlen (lpszVariable) + 1)
{
// If the key=value pair that the executable will look for has NOT yet been inserted
if (!fAddedEnvKeyToChildProcessEnvBlock)
{
// If the current key=value pair from this process' environment block is greater
// than the key=value pair that the executable will look for
//---------------------------------------------------------------------------------
// NOTE: All strings in the environment block must be sorted alphabetically by name.
// The sort is case-insensitive, Unicode order, without regard to locale.
// Because the equal sign is a separator, it must not be used in the name of
// an environment variable.
//---------------------------------------------------------------------------------
if (0 > strEnvKeyValuePairToAddToChildProcessEnvBlock.CompareNoCase (lpszVariable))
{
// Indicate that the key=value pair that the executable will look for has been
// inserted into the environment block for the child process
fAddedEnvKeyToChildProcessEnvBlock = true;
// Insert the next environment block key=value pair
insert_env_block_key_value_pair (
strEnvForChildProcess,
&InsertIdx,
strEnvKeyValuePairToAddToChildProcessEnvBlock.GetBuffer ());
}
}
// Insert the next environment block key=value pair
insert_env_block_key_value_pair (
strEnvForChildProcess,
&InsertIdx,
lpszVariable);
}
// Free the environment block
FreeEnvironmentStrings ((LPTCH)lpvEnv);
}
// If the key=value pair that the executable will look for has NOT yet been inserted
if (!fAddedEnvKeyToChildProcessEnvBlock)
{
// Insert the next environment block key=value pair
insert_env_block_key_value_pair (
strEnvForChildProcess,
&InsertIdx,
strEnvKeyValuePairToAddToChildProcessEnvBlock.GetBuffer ());
}
// Insert the next environment block key=value pair
insert_env_block_key_value_pair (
strEnvForChildProcess,
&InsertIdx,
"\0");
}

View file

@ -0,0 +1,23 @@
class CEnvBlock
{
public:
CEnvBlock (const char * pszToken)
{
memset (&m, 0, sizeof (m));
m.pszToken = pszToken;
}
~CEnvBlock (void)
{
}
void Create (const char * pszEnvKeyToAddToChildProcessEnvBlock,
CString & strEnvForChildProcess);
private:
struct
{
const char * pszToken;
} m;
private:
void insert_env_block_key_value_pair (CString & strEnvForChildProcess,
int * pInsertIdx,
char * lpszVariable);
};

View file

@ -0,0 +1,877 @@
#include "stdafx.h"
static const char szEnvKeyToAddToChildProcessEnvBlock [] = "DisneyOnlineGamesToken";
static const char szInstallerCommandLineOptionPrefix [] = "/";
static const char szInstallerSilentRunModeOption [] = "S";
typedef struct _tag_MMOG_FLAVOR
{
const int mode;
const char * pszInstallerURL;
const char * pszLauncherCSIDL;
const char * pszLauncherPathname;
} MMOG_FLAVOR, *PMMOG_FLAVOR;
static const MMOG_FLAVOR gsc_mmogFlavor [] = {
{
// Development
1,
"http://build64.online.disney.com:3120/english/currentVersion/dev/PotC-setup_DEV.exe",
"PROGRAM_FILES",
"\\Disney\\Disney Online\\PiratesOnline_DEV\\Launcher1.exe",
}
,
{ // QA
2,
"http://pirate143b.starwave.com:1420/english/currentVersion/qa/PotC-setup_QA.exe",
"PROGRAM_FILES",
"\\Disney\\Disney Online\\PiratesOnline_QA\\Launcher1.exe",
}
,
{ // Test
3,
"http://download.test.piratesonline.com/english/currentVersion/PotC-setup_TEST.exe",
"PROGRAM_FILES",
"\\Disney\\Disney Online\\PiratesOnline_TEST\\Launcher1.exe",
}
,
{ // Live
4,
"http://download.piratesonline.com/english/currentVersion/PotC-setup.exe",
"PROGRAM_FILES",
"\\Disney\\Disney Online\\PiratesOnline\\Launcher1.exe",
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static const char c_szFolderNameDelimiter_DOS [] = "\\";
static const char c_chFolderNameDelimiter_UNIX = '/';
#if defined(_DEBUG)
#define ODS(s) { printf (s); printf ("\r\n"); }
#endif
static char *g_paszAcceptTypes [] = { "*/*", NULL };
#if defined(_DEBUG)
PSZ CRunPiratesOnline::get_http_specific_error_description (DWORD dwError)
{
switch (dwError)
{
case 12001:
return "Out of handles";
case 12002:
return "Timeout";
case 12004:
return "Internal Error";
case 12005:
return "Invalid URL";
case 12007:
return "Service Name Not Resolved";
case 12008:
return "Protocol Not Found";
case 12013:
return "Incorrect User Name";
case 12014:
return "Incorrect Password";
case 12015:
return "Login Failure";
case 12016:
return "Invalid Operation";
case 12017:
return "Operation Canceled";
case 12020:
return "Not Proxy Request";
case 12023:
return "No Direct Access";
case 12026:
return "Request Pending";
case 12027:
return "Incorrect Format";
case 12028:
return "Item not found";
case 12029:
return "Cannot connect";
case 12030:
return "Connection Aborted";
case 12031:
return "Connection Reset";
case 12033:
return "Invalid Proxy Request";
case 12034:
return "Need UI";
case 12035:
return "Sec Cert Date Invalid";
case 12038:
return "Sec Cert CN Invalid";
case 12044:
return "Client Auth Cert Needed";
case 12045:
return "Invalid CA Cert";
case 12046:
return "Client Auth Not Setup";
case 12150:
return "HTTP Header Not Found";
case 12152:
return "Invalid HTTP Server Response";
case 12153:
return "Invalid HTTP Header";
case 120154:
return "Invalid Query Request";
case 120156:
return "Redirect Failed";
case 120159:
return "TCP/IP not installed";
default:
return "Error";
}
}
#endif
ENUM_RESPONSE_CODE CRunPiratesOnline::response_data_available_and_successfully_read (HINTERNET hRequest,
char * pszHttpResponseData,
DWORD dwNumHttpResponseDataBufferBytes,
DWORD * pdwNumBytesResponseDataRead)
{
// If we can NOT query the server to determine the amount of data available
DWORD dwNumberOfBytesAvailableToBeRead = 0;
if (!InternetQueryDataAvailable (
hRequest,
&dwNumberOfBytesAvailableToBeRead,
0,
0))
{
#if defined(_DEBUG)
{
DWORD dwLastError;
dwLastError = GetLastError ();
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\t%s: %u=%s",
__FUNCTION__,
"ERROR: InternetQueryDataAvailable",
dwLastError,
get_http_specific_error_description (dwLastError));
ODS(szMsgBuf)
}
#endif
return RESPONSE_CODE__CANNOT_QUERY_SERVER;
}
// If no data is available
if (0 == dwNumberOfBytesAvailableToBeRead)
{
#if defined(_DEBUG)
{
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\t%s: Indicates that zero (0) bytes are available to be read",
__FUNCTION__,
"InternetQueryDataAvailable");
ODS(szMsgBuf)
}
#endif
return RESPONSE_CODE__SUCCESS;
}
// If the number of bytes available to be read is more than the size of our in-memory buffer
if (dwNumberOfBytesAvailableToBeRead > dwNumHttpResponseDataBufferBytes)
{
// Clamp the number of bytes to be read to the size of our in-memory buffer
dwNumberOfBytesAvailableToBeRead = dwNumHttpResponseDataBufferBytes;
}
// If the number of bytes available to be read will require a read past the end of the content
if ((dwNumberOfBytesAvailableToBeRead + m.dwNumBytesResponseDataReadTotal) > m.dwContentLen)
{
// Clip the number of bytes to be read to ensure exactly m.dwContentLen bytes are read
dwNumberOfBytesAvailableToBeRead = m.dwContentLen - m.dwNumBytesResponseDataReadTotal;
}
// If we can NOT read data from the handle opened by function InternetOpenUrl
if (!InternetReadFile (
hRequest,
pszHttpResponseData,
dwNumberOfBytesAvailableToBeRead,
pdwNumBytesResponseDataRead))
{
#if defined(_DEBUG)
{
DWORD dwLastError;
dwLastError = GetLastError ();
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\t%s: %u=%s",
__FUNCTION__,
"ERROR: InternetReadFile",
dwLastError,
get_http_specific_error_description (dwLastError));
ODS(szMsgBuf)
}
#endif
return RESPONSE_CODE__INTERNET_READ_FAILURE;
}
// If the number of byte available to be read is NOT equal to the number of bytes read
if (dwNumberOfBytesAvailableToBeRead != *pdwNumBytesResponseDataRead)
{
#if defined(_DEBUG)
{
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\t%s: The number of bytes available to be read = <%u>, but <%u> bytes were successfully read",
__FUNCTION__,
"ERROR: InternetReadFile",
dwNumberOfBytesAvailableToBeRead,
*pdwNumBytesResponseDataRead);
ODS(szMsgBuf)
}
#endif
return RESPONSE_CODE__INVALID_NUMBER_OF_BYTES_READ;
}
#if defined(_DEBUG)
{
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\tSuccessfully read <%d> bytes",
__FUNCTION__,
*pdwNumBytesResponseDataRead);
ODS(szMsgBuf)
}
#endif
// Indicate success
return RESPONSE_CODE__SUCCESS;
}
ENUM_RESPONSE_CODE CRunPiratesOnline::download_installer (HANDLE hFile)
{
#if defined(_DEBUG)
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"ENTER: "
"%s",__FUNCTION__);ODS(szMsgBuf)}
#endif
ENUM_RESPONSE_CODE enumResponseCode = RESPONSE_CODE__SUCCESS;
//
char hostnamebuf [512];
memset (hostnamebuf, 0, sizeof (hostnamebuf));
//
char urlstrbuf [1024];
//
URL_COMPONENTS url_comp;
memset (&url_comp, 0, sizeof (url_comp));
url_comp.dwStructSize = sizeof (url_comp);
url_comp.lpszHostName = hostnamebuf;
url_comp.dwHostNameLength = sizeof (hostnamebuf);
url_comp.lpszUrlPath = urlstrbuf;
url_comp.dwUrlPathLength = sizeof (urlstrbuf);
// If the source URL cannot be cracked into its component parts
#if defined(_DEBUG)
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call InternetCrackUrl",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (!InternetCrackUrl (gsc_mmogFlavor[m.immogFlavorIdx].pszInstallerURL, 0, 0x0, &url_comp))
{
#if defined(_DEBUG)
{
DWORD dwLastError;
dwLastError = GetLastError ();
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s\t"
"%s: %u=%s",
__FUNCTION__,
"ERROR: InternetCrackUrl",
dwLastError,
get_http_specific_error_description (dwLastError));
ODS(szMsgBuf)
}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_CRACK_SOURCE_URL;
}
else
if ((url_comp.nScheme != INTERNET_SCHEME_HTTP)
&&
(url_comp.nScheme != INTERNET_SCHEME_HTTPS)
)
{
#if defined(_DEBUG)
{
char szMsgBuf [1024];
wsprintf (
szMsgBuf,
"%s"
"\t"
"ERROR: Only HTTP and HTTPS are supported",
__FUNCTION__);
ODS(szMsgBuf)
}
#endif
enumResponseCode = RESPONSE_CODE__UNSUPPORTED_INTERNET_PROTOCOL_SCHEME;
}
// Initialize the HttpOpenRequest bit flags
//
DWORD dwHttpOpenRequestBitFlags =
INTERNET_FLAG_RELOAD // 0x80000000 // retrieve the original item
|
INTERNET_FLAG_NO_CACHE_WRITE // 0x04000000 // don't write this item to the cache
|
INTERNET_FLAG_KEEP_CONNECTION // 0x00400000 // use keep-alive semantics
|
INTERNET_FLAG_PRAGMA_NOCACHE // 0x00000100 // asking wininet to add "pragma: no-cache"
;
// Set the server port number
//
if (INTERNET_SCHEME_HTTPS == url_comp.nScheme)
{
dwHttpOpenRequestBitFlags |= (
INTERNET_FLAG_SECURE // 0x00800000 // use PCT/SSL if applicable (HTTP)
|
INTERNET_FLAG_IGNORE_CERT_CN_INVALID // 0x00001000 // bad common name in X509 Cert.
|
INTERNET_FLAG_IGNORE_CERT_DATE_INVALID); // 0x00002000 // expired X509 Cert.
}
HINTERNET hSession;
HINTERNET hConnection = NULL;
HINTERNET hRequest = NULL;
//
#define MAX_HEADER_SIZE 8192
char * pRequestHdrBuf = new char [MAX_HEADER_SIZE];
DWORD dwBufLen = MAX_HEADER_SIZE;
//
DWORD HTTP_StatusCode = 0;
DWORD dwSizeOfStatusCode = sizeof (HTTP_StatusCode);
//
DWORD dwSizeOf_ContentLen = sizeof (m.dwContentLen);
// Initialize this apps use of the WinINet functions
#if defined(_DEBUG)
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call InternetOpen",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (NULL == (hSession = InternetOpen (
"DisneyOnlineGames",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0)))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: InternetOpen",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_OPEN_SESSION;
}
// Open an HTTP session for the specified site
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - url_comp.lpszHostName=[%s]",__FUNCTION__,url_comp.lpszHostName);ODS(szMsgBuf)}
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - url_comp.nPort=[%d]",__FUNCTION__,url_comp.nPort);ODS(szMsgBuf)}
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - urlstrbuf=[%s]",__FUNCTION__,urlstrbuf);ODS(szMsgBuf)}
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call InternetConnect",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (NULL == (hConnection = InternetConnect (
hSession,
url_comp.lpszHostName,
url_comp.nPort,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
INTERNET_FLAG_NO_CACHE_WRITE,
0)))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: InternetConnect",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_CONNECT;
}
// Open an HTTP request handle
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call HttpOpenRequest",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (NULL == (hRequest = HttpOpenRequest (
hConnection,
"GET",
url_comp.lpszUrlPath,
"HTTP/1.1",
NULL,
(LPCTSTR *)g_paszAcceptTypes,
dwHttpOpenRequestBitFlags,
0)))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpOpenRequest",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_OPEN_REQUEST;
}
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call HttpQueryInfo",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (!HttpQueryInfo (
hRequest,
HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS,
(LPVOID)pRequestHdrBuf,
&dwBufLen,
0))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpQueryInfo",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_OBTAIN_HEADERS_RETURNED_BY_SERVER;
}
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call HttpSendRequest",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (!HttpSendRequest (
hRequest,
NULL, // No extra headers
0, // No extra Header length
NULL, // Not sending a POST
0)) // Not sending a POST
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpQueryInfo",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__HTTP_SERVER_REQUEST_FAILURE;
}
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call HttpQueryInfo",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (!HttpQueryInfo (
hRequest,
HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, // HTTP_QUERY_FLAG_NUMBER tells it to return a dword, not a string
(LPVOID)&HTTP_StatusCode,
&dwSizeOfStatusCode,
NULL))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpQueryInfo",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_OBTAIN_STATUS_CODE;
}
else if (HTTP_STATUS_OK != HTTP_StatusCode)
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpQueryInfo",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__HTTP_STATUS_ERROR;
}
else
#if defined(_DEBUG)
{
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"%s"
" - about to call HttpQueryInfo",__FUNCTION__);ODS(szMsgBuf)}
#endif
if (!HttpQueryInfo (
hRequest,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
(LPVOID)&(m.dwContentLen),
&dwSizeOf_ContentLen,
NULL))
{
#if defined(_DEBUG)
{DWORD dwLastError;dwLastError = GetLastError ();char szMsgBuf [1024];wsprintf (szMsgBuf,"%s\t"
"%s: %u=%s",__FUNCTION__,"ERROR: HttpQueryInfo",dwLastError,get_http_specific_error_description (dwLastError));ODS(szMsgBuf)}
#endif
enumResponseCode = RESPONSE_CODE__CANNOT_OBTAIN_CONTENT_LENGTH;
}
else
{
// While response data is available is being successfully read
//
static const int NUM_HTTP_RESPONSE_DATA_BUFFER_BYTES = 8192;
char szHttpResponseData [NUM_HTTP_RESPONSE_DATA_BUFFER_BYTES];
DWORD dwNumBytesResponseDataRead = 0;
ENUM_RESPONSE_CODE enumResponseCode;
while (
(m.dwNumBytesResponseDataReadTotal < m.dwContentLen)
&&
(RESPONSE_CODE__SUCCESS == (enumResponseCode = response_data_available_and_successfully_read (
hRequest,
szHttpResponseData,
NUM_HTTP_RESPONSE_DATA_BUFFER_BYTES,
&dwNumBytesResponseDataRead)))
)
{
// Update the total number of response data bytes read
m.dwNumBytesResponseDataReadTotal += dwNumBytesResponseDataRead;
// If the destination file write fails
DWORD dwNumberOfBytesWritten;
if (!WriteFile (
hFile,
szHttpResponseData,
dwNumBytesResponseDataRead,
&dwNumberOfBytesWritten,
NULL))
{
enumResponseCode = RESPONSE_CODE__FILE_WRITE_FAILURE;
break;
}
if (dwNumBytesResponseDataRead != dwNumberOfBytesWritten)
{
enumResponseCode = RESPONSE_CODE__UNEXPECTED_NUMBER_OF_BYTES_WRITTEN_TO_FILE;
break;
}
}
}
#if defined(_DEBUG)
}
}
}
}
}
}
#endif
// Close the handle opened by the call to function HttpOpenRequest
//
if (hRequest)
{
InternetCloseHandle (hRequest);
}
// Close the handle opened by the call to function InternetConnect
//
if (hConnection)
{
InternetCloseHandle (hConnection);
}
// Close the Internet handle opened by the call to function InternetOpen
//
if (hSession)
{
InternetCloseHandle (hSession);
}
#if defined(_DEBUG)
{ char szMsgBuf [1024];wsprintf (szMsgBuf,"LEAVE: "
"%s",__FUNCTION__);ODS(szMsgBuf)}
#endif
return enumResponseCode;
}
ENUM_RESPONSE_CODE CRunPiratesOnline::download_and_run_installer (const char * pszInstallerURL)
{
// If the request to obtain the path to temporary directory failed
char szTempPath [MAX_PATH];
if (0 == GetTempPath (MAX_PATH, szTempPath))
{
return RESPONSE_CODE__UNABLE_TO_OBTAIN_TEMP_PATHNAME;
}
// If the request to obtain a unique temporary filename failed
char szInstallerFullPathname [MAX_PATH];
if (0 == GetTempFileName (szTempPath, NULL, 0, szInstallerFullPathname))
{
return RESPONSE_CODE__UNABLE_TO_OBTAIN_TEMP_FILENAME;
}
// If the temporary file was not successfully opened for writing
HANDLE hFile;
if (INVALID_HANDLE_VALUE == (hFile = CreateFile (
szInstallerFullPathname,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
)))
{
return RESPONSE_CODE__UNABLE_TO_CREATE_DESTINATION_FILENAME;
}
//
ENUM_RESPONSE_CODE enumResponseCode;
enumResponseCode = download_installer (hFile);
//
if (!CloseHandle (hFile))
{
enumResponseCode = RESPONSE_CODE__CANNOT_CLOSE_DESTINATION_FILE;
}
//
if (RESPONSE_CODE__SUCCESS != enumResponseCode)
{
DeleteFile (szInstallerFullPathname);
return enumResponseCode;
}
// Register file szInstallerFullPathname to be deleted when the system restarts
// NOTES:
// 1) The system moves the file immediately after AUTOCHK is executed, but before creating any
// paging files.
// 2) Parameter value MOVEFILE_DELAY_UNTIL_REBOOT can be used only if the process is in the
// context of a user who belongs to the administrator group or the LocalSystem account.
MoveFileEx (szInstallerFullPathname, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
// Set command line
CString strCommandLine (szInstallerFullPathname);
strCommandLine.Append (" ");
strCommandLine.Append (szInstallerCommandLineOptionPrefix);
strCommandLine.Append (szInstallerSilentRunModeOption);
strCommandLine.Append (" ");
strCommandLine.Append (szInstallerCommandLineOptionPrefix);
strCommandLine.Append (szEnvKeyToAddToChildProcessEnvBlock);
strCommandLine.Append (" ");
strCommandLine.Append (m.pszToken);
// Attempt to run the installer executable
return create_process (strCommandLine);
}
ENUM_RESPONSE_CODE CRunPiratesOnline::create_process (CString & strCommandLine)
{
// Create security attributes
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), &sd, true };
// Create child process environment block
CString strEnvForChildProcess;
CEnvBlock EnvBlock (m.pszToken);
EnvBlock.Create (szEnvKeyToAddToChildProcessEnvBlock, strEnvForChildProcess);
// Set startup information
STARTUPINFO si;
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
// Initialize process information structure
PROCESS_INFORMATION pi;
ZeroMemory (&pi, sizeof (pi));
// Attempt to run the executable
if (!CreateProcess (
NULL,
strCommandLine.GetBuffer (),
&sa,
&sa,
true,
0,
strEnvForChildProcess.GetBuffer (),
NULL,
&si,
&pi))
{
return RESPONSE_CODE__CREATE_PROCESS_FAILED;
}
return RESPONSE_CODE__SUCCESS;
}
bool CRunPiratesOnline::map_folder_to_csidl (const char * pszCSIDL,
int * pcsidl)
{
bool fRet = true;
//
*pcsidl = 0;
if (0 == _strcmpi (pszCSIDL /* .GetBuffer () */ , "ADMINTOOLS"))
{
// The file system directory that is used to store administrative tools for an individual user.
// The Microsoft Management Console (MMC) will save customized consoles to this directory, and
// it will roam with the user.
*pcsidl |= CSIDL_ADMINTOOLS;
}
else
if (0 == _strcmpi (pszCSIDL, "COMMON_ADMINTOOLS"))
{
// The file system directory containing administrative tools for all users of the computer.
*pcsidl |= CSIDL_COMMON_ADMINTOOLS;
}
else
if (0 == _strcmpi (pszCSIDL, "APPDATA"))
{
// The file system directory that serves as a common repository for application-specific data.
// A typical path is C:\Documents and Settings\username\Application Data.
// This CSIDL is supported by the redistributable Shfolder.dll for systems that do not have
// the Microsoft Internet Explorer 4.0 integrated Shell installed.
*pcsidl |= CSIDL_APPDATA;
}
else
if (0 == _strcmpi (pszCSIDL, "COMMON_APPDATA"))
{
// The file system directory containing application data for all users.
// A typical path is C:\Documents and Settings\All Users\Application Data.
*pcsidl |= CSIDL_COMMON_APPDATA;
}
else
if (0 == _strcmpi (pszCSIDL, "COMMON_DOCUMENTS"))
{
// The file system directory that contains documents that are common to all users.
// A typical paths is C:\Documents and Settings\All Users\Documents.
// Valid for Windows NT systems and Microsoft Windows 95 and Windows 98 systems with
// Shfolder.dll installed.
*pcsidl |= CSIDL_COMMON_DOCUMENTS;
}
else
if (0 == _strcmpi (pszCSIDL, "COOKIES"))
{
// The file system directory that serves as a common repository for Internet cookies.
// A typical path is C:\Documents and Settings\username\Cookies.
*pcsidl |= CSIDL_COOKIES;
}
else
if (0 == _strcmpi (pszCSIDL, "HISTORY"))
{
// The file system directory that serves as a common repository for Internet history items.
*pcsidl |= CSIDL_HISTORY;
}
else
if (0 == _strcmpi (pszCSIDL, "INTERNET_CACHE"))
{
// The file system directory that serves as a common repository for temporary Internet files.
// A typical path is C:\Documents and Settings\username\Local Settings\Temporary Internet Files.
*pcsidl |= CSIDL_INTERNET_CACHE;
}
else
if (0 == _strcmpi (pszCSIDL, "LOCAL_APPDATA"))
{
// The file system directory that serves as a data repository for local (nonroaming) applications.
// A typical path is C:\Documents and Settings\username\Local Settings\Application Data.
*pcsidl |= CSIDL_LOCAL_APPDATA;
}
else
if (0 == _strcmpi (pszCSIDL, "MYPICTURES"))
{
// The file system directory that serves as a common repository for image files.
// A typical path is C:\Documents and Settings\username\My Documents\My Pictures.
*pcsidl |= CSIDL_MYPICTURES;
}
else
if (0 == _strcmpi (pszCSIDL, "PERSONAL"))
{
// The virtual folder representing the My Documents desktop item.
// This is equivalent to CSIDL_MYDOCUMENTS.
*pcsidl |= CSIDL_PERSONAL;
}
else
if (0 == _strcmpi (pszCSIDL, "PROGRAM_FILES"))
{
// The Program Files folder.
// A typical path is C:\Program Files.
*pcsidl |= CSIDL_PROGRAM_FILES;
}
else
if (0 == _strcmpi (pszCSIDL, "PROGRAM_FILES_COMMON"))
{
// A folder for components that are shared across applications.
// A typical path is C:\Program Files\Common.
// Valid only for Windows NT, Windows 2000, and Windows XP systems.
// Not valid for Windows Millennium Edition (Windows Me).
*pcsidl |= CSIDL_PROGRAM_FILES_COMMON;
}
else
if (0 == _strcmpi (pszCSIDL, "SYSTEM"))
{
// The Windows System folder.
// A typical path is C:\Windows\System32.
*pcsidl |= CSIDL_SYSTEM;
}
else
if (0 == _strcmpi (pszCSIDL, "WINDOWS"))
{
// The Windows directory or SYSROOT.
// This corresponds to the %windir% or %SYSTEMROOT% environment variables.
// A typical path is C:\Windows.
*pcsidl |= CSIDL_WINDOWS;
}
else
{
fRet = false;
}
return fRet;
}
ENUM_RESPONSE_CODE CRunPiratesOnline::run_launcher (const char * pszLauncherCSIDL,
const char * pszLauncherPathname)
{
// Given a CSIDL as a string, if the corresponding pathname cannot be obtained
int csidl = 0;
if (!map_folder_to_csidl (pszLauncherCSIDL, &csidl))
{
return RESPONSE_CODE__UNRECOGNIZED_DESTINATION_FOLDER;
}
// Given a CSIDL of a folder, if a path was NOT returned
char szPathFromCSIDL [MAX_PATH];
if (!(SUCCEEDED(SHGetFolderPath (
NULL, // handle to an owner window
csidl, // CSIDL value that identifies the folder whose path is to be retrieved
NULL, // access token that can be used to represent a particular user
SHGFP_TYPE_CURRENT, // flags to specify which path is to be returned
szPathFromCSIDL // pointer to a null-terminated string of length MAX_PATH which will receive the path
))))
{
return RESPONSE_CODE__CANNOT_OBTAIN_SPECIAL_ROOT_FOLDER_PATHNAME;
}
// Obtain string lengths
size_t stPath_Len = strlen (szPathFromCSIDL);
size_t stLancherPathname_Len = strlen (pszLauncherPathname);
// If launcher executable full pathname will be too long
if (MAX_PATH <= (stPath_Len + stLancherPathname_Len))
{
return RESPONSE_CODE__LAUNCHER_FULL_PATHNAME_TOO_LONG;
}
// Set launcher executable full pathname
char szLauncherFullPathname [MAX_PATH];
strcpy (szLauncherFullPathname, szPathFromCSIDL);
strcat (szLauncherFullPathname, pszLauncherPathname);
// Set command line
CString strCommandLine (szLauncherFullPathname);
strCommandLine.Append (" ");
strCommandLine.Append (szEnvKeyToAddToChildProcessEnvBlock);
strCommandLine.Append ("=");
strCommandLine.Append (m.pszToken);
// Return indication of whether or not the launcher process was successfully created
return create_process (strCommandLine);
}
ENUM_RESPONSE_CODE CRunPiratesOnline::validate_inputs (const int ModeId)
{
ENUM_RESPONSE_CODE enumResponseCode = RESPONSE_CODE__INVALID_MODE;
for (m.immogFlavorIdx = 0; m.immogFlavorIdx < (sizeof (gsc_mmogFlavor) / sizeof (MMOG_FLAVOR)); m.immogFlavorIdx++)
{
if (gsc_mmogFlavor[m.immogFlavorIdx].mode == ModeId)
{
enumResponseCode = RESPONSE_CODE__SUCCESS;
break;
}
}
return enumResponseCode;
}
ULONG CRunPiratesOnline::Run (const int ModeId,
const char * pszToken)
{
m.pszToken = pszToken;
ENUM_RESPONSE_CODE ResponseCode;
if (RESPONSE_CODE__SUCCESS == (ResponseCode = validate_inputs (ModeId)))
{
if (RESPONSE_CODE__SUCCESS != (ResponseCode = run_launcher (
gsc_mmogFlavor[m.immogFlavorIdx].pszLauncherCSIDL,
gsc_mmogFlavor[m.immogFlavorIdx].pszLauncherPathname)))
{
ResponseCode = download_and_run_installer (
gsc_mmogFlavor[m.immogFlavorIdx].pszInstallerURL);
}
}
return ResponseCode;
}

View file

@ -0,0 +1,130 @@
#pragma once
enum ENUM_RESPONSE_CODE
{
RESPONSE_CODE__SUCCESS = 0,
// Success
RESPONSE_CODE__INVALID_MODE = 1,
// Mode input is invalid
RESPONSE_CODE__UNRECOGNIZED_DESTINATION_FOLDER = 2,
// Unrecognized Destination Folder argument
// Please reference [Valid Destination Folder Parameter Values] below
RESPONSE_CODE__CANNOT_OBTAIN_SPECIAL_ROOT_FOLDER_PATHNAME = 3,
// Cannot obtain special root folder pathname
RESPONSE_CODE__LAUNCHER_FULL_PATHNAME_TOO_LONG = 4,
// Full pathname to launcher executable is too long
RESPONSE_CODE__BAD_PATHNAME = 5,
// Possible issue: Relative paths are not allowed
RESPONSE_CODE__FILENAME_EXCED_RANGE = 6,
// Destination Folder + Destination Sub-folder + Destination Filename > 256 characters
RESPONSE_CODE__PATH_NOT_FOUND = 7,
// The system cannot find the path
// Possible issue: The path contains an invalid entry
RESPONSE_CODE__CANCELLED = 8,
// The user canceled the operation
RESPONSE_CODE__SHCDEX_UNRECOGNIZED_RET_CODE = 9,
// Call to create Destination Folder failed with an unrecognized reason code
RESPONSE_CODE__DESTINATION_FILENAME_TOO_LONG = 10,
// Destination filename too long
RESPONSE_CODE__DESTINATION_FILENAME_IS_A_DIRECTORY = 11,
// A directory exists with the same full pathname as the requested destination
RESPONSE_CODE__UNABLE_TO_CREATE_DESTINATION_FILENAME = 12,
// Unable to create destination file on user's HDD
RESPONSE_CODE__CANNOT_CRACK_SOURCE_URL = 13,
// Cannot crack source URL
RESPONSE_CODE__UNSUPPORTED_INTERNET_PROTOCOL_SCHEME = 14,
// Internet protocol scheme not supported
// Supported Internet protocol schemes: HTTP, HTTPS
RESPONSE_CODE__CANNOT_OBTAIN_CONTENT_LENGTH = 15,
// Cannot obtain content length from server
RESPONSE_CODE__CANNOT_OPEN_SESSION = 16,
// Call to open protocol session failed
RESPONSE_CODE__CANNOT_CONNECT = 17,
// Attempt to connect to server failed
RESPONSE_CODE__CANNOT_OPEN_REQUEST = 18,
// Protocol request handle creation failure
RESPONSE_CODE__CANNOT_OBTAIN_HEADERS_RETURNED_BY_SERVER = 19,
// Unable to retrieve header information associated with server request
RESPONSE_CODE__HTTP_SERVER_REQUEST_FAILURE = 20,
// Server request failure
RESPONSE_CODE__CANNOT_OBTAIN_STATUS_CODE = 21,
// Server request could not complete
RESPONSE_CODE__HTTP_STATUS_ERROR = 22,
// Status code returned from server indicates error
RESPONSE_CODE__CANNOT_QUERY_SERVER = 23,
// Cannot query server
// Failure occurred when querying server to determine data size
RESPONSE_CODE__INTERNET_READ_FAILURE = 24,
// Call to read data from server failed
RESPONSE_CODE__INVALID_NUMBER_OF_BYTES_READ = 25,
// The number of bytes requested to be read is not equal to the number of bytes read from
// the server
RESPONSE_CODE__FILE_WRITE_FAILURE = 26,
// HDD write failure
// Users hard drive may be out of space
RESPONSE_CODE__UNEXPECTED_NUMBER_OF_BYTES_WRITTEN_TO_FILE = 27,
// Number of bytes written to HDD does not match the number of bytes requested to be written
RESPONSE_CODE__CANNOT_CLOSE_DESTINATION_FILE = 28,
// Call to close the Destination Filename failed
RESPONSE_CODE__CREATE_PROCESS_FAILED = 29,
// Unable to run downloaded executable
//
//
RESPONSE_CODE__UNABLE_TO_OBTAIN_TEMP_PATHNAME = 51,
RESPONSE_CODE__UNABLE_TO_OBTAIN_TEMP_FILENAME = 52,
//
//
RESPONSE_CODE__FAILURE = 99,
// Non-specific failure
};
class CRunPiratesOnline
{
public:
CRunPiratesOnline (void)
{
memset (&m, 0, sizeof (m));
}
~CRunPiratesOnline (void)
{
}
ULONG Run (const int ModeId,
const char * pszToken);
private:
struct
{
const char * pszToken;
int immogFlavorIdx;
DWORD dwContentLen;
DWORD dwNumBytesResponseDataReadTotal;
} m;
private:
#if defined(_DEBUG)
PSZ get_http_specific_error_description (DWORD dwError);
#endif
//
ENUM_RESPONSE_CODE response_data_available_and_successfully_read (HINTERNET hRequest,
char * pszHttpResponseData,
DWORD dwNumHttpResponseDataBufferBytes,
DWORD * pdwNumBytesResponseDataRead);
//
ENUM_RESPONSE_CODE download_installer (HANDLE hFile);
//
ENUM_RESPONSE_CODE download_and_run_installer (const char * pszInstallerURL);
//
void insert_env_block_key_value_pair (CString & strEnvForChildProcess,
int * pInsertIdx,
char * lpszVariable);
//
void create_child_process_environment_block (CString & strEnvForChildProcess);
//
ENUM_RESPONSE_CODE create_process (CString & strCommandLine);
//
ENUM_RESPONSE_CODE validate_inputs (const int ModeId);
//
ENUM_RESPONSE_CODE run_launcher (const char * pszLauncherCSIDL,
const char * pszLauncherPathname);
//
bool map_folder_to_csidl (const char * pszCSIDL,
int * pcsidl);
};

View file

@ -0,0 +1,69 @@
#include "StdAfx.h"
#define INITIAL_NUM_WINDOW_HANDLES 10
#define NUM_WINDOW_HANDLE_ARRAY_INCREMENT 5
CTopLevelWindowIterator::CTopLevelWindowIterator (DWORD dwProcessId)
{
ZeroMemory (&m, sizeof (m));
m.dwProcessId = dwProcessId;
m.dwNumAlloced = INITIAL_NUM_WINDOW_HANDLES;
m.paHWND = new HWND [m.dwNumAlloced];
}
CTopLevelWindowIterator::~CTopLevelWindowIterator()
{
delete [] m.paHWND;
}
HWND CTopLevelWindowIterator::First()
{
// Enumerate all top-level windows
::EnumWindows(EnumProc, (LPARAM)this);
// Reset the HWND array current index
m.dwCurrIdx = 0;
// Return the first top level window created by the specified process
return Next();
}
HWND CTopLevelWindowIterator::Next()
{
if (m.paHWND && (m.dwCurrIdx < m.dwNumUsed))
{
return m.paHWND[m.dwCurrIdx++];
}
return NULL;
}
BOOL CALLBACK CTopLevelWindowIterator::EnumProc (HWND hwnd, LPARAM lp)
{
return ((CTopLevelWindowIterator*)lp)->OnEnumProc(hwnd);
}
BOOL CTopLevelWindowIterator::OnEnumProc (HWND hwnd)
{
// If the given top level window is visible
if (WS_VISIBLE & GetWindowLong (hwnd, GWL_STYLE))
{
// Retrieve the identifier of the process that created the given top level window
DWORD dwWindowThreadProcessId;
GetWindowThreadProcessId (hwnd, &dwWindowThreadProcessId);
// If the given top level window was created by the specified process
if (dwWindowThreadProcessId == m.dwProcessId)
{
if (m.dwNumUsed >= m.dwNumAlloced)
{
HWND * paHWND = new HWND [m.dwNumAlloced + NUM_WINDOW_HANDLE_ARRAY_INCREMENT];
memcpy (paHWND, m.paHWND, sizeof (HWND) * m.dwNumAlloced);
delete [] m.paHWND;
m.paHWND = paHWND;
m.dwNumAlloced += NUM_WINDOW_HANDLE_ARRAY_INCREMENT;
}
m.paHWND[m.dwNumUsed++] = hwnd;
}
}
return TRUE; // keep looking
}

View file

@ -0,0 +1,23 @@
class CTopLevelWindowIterator
{
public:
CTopLevelWindowIterator(DWORD dwProcessId);
~CTopLevelWindowIterator();
HWND First();
HWND Next();
protected:
static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM lp);
BOOL OnEnumProc(HWND hwnd);
struct
{
DWORD dwProcessId; // process id
DWORD dwNumAlloced; // number of HWND array elements allocated
DWORD dwNumUsed; // number of HWND array elements used
DWORD dwCurrIdx; // HWND array current index
HWND * paHWND; // pointer to the array of top level window handles
} m;
};

View file

@ -0,0 +1,20 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by DisneyOnlineGames.rc
//
#define IDS_DISNEYONLINEGAMES 1
#define IDS_DISNEYONLINEGAMES_PPG 2
#define IDS_DISNEYONLINEGAMES_PPG_CAPTION 200
#define IDD_PROPPAGE_DISNEYONLINEGAMES 200
#define IDB_DISNEYONLINEGAMES 1
#define _APS_NEXT_RESOURCE_VALUE 201
#define _APS_NEXT_CONTROL_VALUE 201
#define _APS_NEXT_SYMED_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 32768

View file

@ -0,0 +1 @@
#include "stdafx.h"

View file

@ -0,0 +1,55 @@
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#ifndef VC_EXTRALEAN
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#endif
#ifndef WINVER
#define WINVER 0x0501
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#ifndef _WIN32_IE
#define _WIN32_IE 0x0600
#endif
#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit
#include <afxctl.h> // MFC support for ActiveX Controls
#include <afxext.h> // MFC extensions
#ifndef _AFX_NO_OLE_SUPPORT
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Comon Controls
#endif
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
// Delete the two includes below if you do not wish to use the MFC
// database classes
#ifndef _WIN64
#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h> // MFC ODBC database classes
#endif // _AFX_NO_DB_SUPPORT
#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h> // MFC DAO database classes
#endif // _AFX_NO_DAO_SUPPORT
#endif // _WIN64
#include <shlobj.h>
#include <afxwin.h>
#include <wininet.h>
#include <process.h>
#include "EnvBlock.h"
#include "RunPiratesOnline.h"
#include "TopLevelWindowIterator.h"

View file

@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testCoreFunctionality", "testCoreFunctionality.Visual Studio 2005.vcproj", "{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}.Debug|Win32.ActiveCfg = Debug|Win32
{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}.Debug|Win32.Build.0 = Debug|Win32
{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}.Release|Win32.ActiveCfg = Release|Win32
{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,246 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="testCoreFunctionality"
ProjectGUID="{72EC3673-7D59-4A82-8BFA-ABF504A3DA87}"
RootNamespace="testCoreFunctionality"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
TreatWChar_tAsBuiltInType="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wininet.lib"
OutputFile="$(OutDir)/testCoreFunctionality.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
AssemblyDebug="1"
ProgramDatabaseFile="$(OutDir)/testCoreFunctionality.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="wininet.lib"
OutputFile="$(OutDir)/testCoreFunctionality.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\src\EnvBlock.cpp"
>
</File>
<File
RelativePath="..\src\RunPiratesOnline.cpp"
>
</File>
<File
RelativePath="..\src\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\testCoreFunctionality.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\src\EnvBlock.h"
>
</File>
<File
RelativePath="..\src\RunPiratesOnline.h"
>
</File>
<File
RelativePath="..\src\stdafx.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,18 @@
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
CRunPiratesOnline * pRunPiratesOnline = new CRunPiratesOnline ();
ULONG ResponseCode = pRunPiratesOnline->Run (
3,
"UserPassiveToken");
delete pRunPiratesOnline;
// Wait for user to read output
fflush (stdin);
printf ("ResponseCode=[%u]\r\n",ResponseCode);
printf ("Press ENTER key to exit: ");
while ('\n' != fgetc (stdin))
//
return 1;
}

View file

@ -0,0 +1,99 @@
#include "stdafx.h"
static void dump_env_block (void)
{
printf ("%s: ENTER\n\n", __FUNCTION__);
// If a pointer to the environment block for this process was returned
LPVOID lpvEnv;
if (lpvEnv = GetEnvironmentStrings ())
{
// Variable strings are separated by NULL byte, and the block is terminated by a NULL byte
LPTSTR lpszVariable;
for (lpszVariable = (LPTSTR)lpvEnv; *lpszVariable; lpszVariable += lstrlen (lpszVariable) + 1)
{
printf ("%s\n", lpszVariable);
}
// Free the environment block
FreeEnvironmentStrings ((LPTCH)lpvEnv);
}
printf ("%s: LEAVE\n\n", __FUNCTION__);
}
#if defined(_DEBUG)
static bool create_process (char * pszProcessFullPathname,
const char * pszCommandLineArgs = NULL)
{
CString strCommandLine (pszProcessFullPathname);
if (pszCommandLineArgs)
{
strCommandLine.Append (pszCommandLineArgs);
}
// Create security attributes
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), &sd, true };
//
dump_env_block ();
//
// Create child process environment block
CString strEnvForChildProcess;
CEnvBlock EnvBlock ("U2FsdGVkX19W1vR0iRQVBG4VBp%2BW%2FAqGiGri5SHhJQK3NSA3yrMbrKPXp7PpBiQiRR5njCGoyRsK1f6xRlPFqMI3iSk%2B5MhrkZ6ycQOCazyNcKCc9ZtS13MEsia8cKFwjybX6%2F4BV09dGIjB47jHDD5VCs7K6bLxUZXTnLD88OU7v8FeLaI3ds%2B25bzD3k%2FGYFethATY6Fr6P6EsWKlN8FFVkPsD6Rmfm9hsGxK52cBzsZHCsJ%2BvV9Z7GQZqIoV43XwtAOeeIgC%2FeKJZ%2BTdxxWuby3pS4YEAOf2o37d68CeMLZTeQQR2Ul1APEv19erfvBAg%2FT1DXbJH78CEkxe9x99dOsDrb%2BWd91kuDy9baIkEXtFAcP6DMsP%2FUyCoC%2B2taZD5vIBMOuxIUWcdTulB3A%3D%3D");
EnvBlock.Create ("BobJones", strEnvForChildProcess);
//
printf ("%s: About to write strEnvForChildProcess\n\n", __FUNCTION__);
LPTSTR lpszVar;
for (lpszVar = strEnvForChildProcess.GetBuffer (); *lpszVar; lpszVar += lstrlen (lpszVar) + 1)
{
printf ("%s\n", lpszVar);
}
printf ("%s: Wrote strEnvForChildProcess\n\n", __FUNCTION__);
//
// Set startup information
STARTUPINFO si;
memset (&si, 0, sizeof (si));
si.cb = sizeof (si);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOWNORMAL;
// Initialize process information structure
PROCESS_INFORMATION pi;
ZeroMemory (&pi, sizeof (pi));
// Attempt to run the executable
if (!CreateProcess (
NULL,
strCommandLine.GetBuffer (),
&sa,
&sa,
true,
0,
strEnvForChildProcess.GetBuffer (),
NULL,
&si,
&pi))
{
return false;
}
return true;
}
#endif
int main(int argc, char * argv[])
{
printf ("%s: ENTER\n\n", __FUNCTION__);
#if defined(_DEBUG)
char szProcessToCreate [] = "Release\\testEnvBlock.exe";
if (!create_process (szProcessToCreate))
{
printf ("Unable to create process \"%s\"", szProcessToCreate);
}
#else
dump_env_block ();
#endif
// Wait for user to read output
fflush (stdin);
printf ("\n\nPress ENTER key to exit: ");
while ('\n' != fgetc (stdin))
//
printf ("%s: LEAVE\n\n", __FUNCTION__);
return 1;
}

View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testEnvBlock", "testEnvBlock.vcproj", "{2582CF1E-D27B-4824-B200-9F5EDC1836BA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2582CF1E-D27B-4824-B200-9F5EDC1836BA}.Debug|Win32.ActiveCfg = Debug|Win32
{2582CF1E-D27B-4824-B200-9F5EDC1836BA}.Debug|Win32.Build.0 = Debug|Win32
{2582CF1E-D27B-4824-B200-9F5EDC1836BA}.Release|Win32.ActiveCfg = Release|Win32
{2582CF1E-D27B-4824-B200-9F5EDC1836BA}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="testEnvBlock"
ProjectGUID="{2582CF1E-D27B-4824-B200-9F5EDC1836BA}"
RootNamespace="testEnvBlock"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="StdAfx.h"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(ProjectName)__DEBUG__.exe"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\src\EnvBlock.cpp"
>
</File>
<File
RelativePath="..\src\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\testEnvBlock.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath="..\src\EnvBlock.h"
>
</File>
<File
RelativePath="..\src\stdafx.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1 @@
#include "stdafx.h"

View file

@ -0,0 +1,9 @@
#pragma once
#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <windows.h>
#include "..\src\TopLevelWindowIterator.h"

View file

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testTopLevelWindowIterator", "testTopLevelWindowIterator.VS2005.vcproj", "{C275C319-F39C-4728-81C4-B16279EEC848}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C275C319-F39C-4728-81C4-B16279EEC848}.Debug|Win32.ActiveCfg = Debug|Win32
{C275C319-F39C-4728-81C4-B16279EEC848}.Debug|Win32.Build.0 = Debug|Win32
{C275C319-F39C-4728-81C4-B16279EEC848}.Release|Win32.ActiveCfg = Release|Win32
{C275C319-F39C-4728-81C4-B16279EEC848}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="testTopLevelWindowIterator"
ProjectGUID="{C275C319-F39C-4728-81C4-B16279EEC848}"
RootNamespace="testTopLevelWindowIterator"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\testTopLevelWindowIterator.cpp"
>
</File>
<File
RelativePath="..\src\TopLevelWindowIterator.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\stdafx.h"
>
</File>
<File
RelativePath="..\src\TopLevelWindowIterator.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -0,0 +1,12 @@
#include "stdafx.h"
int main(int argc, char* argv[])
{
DWORD dwProcessId = 0;
CTopLevelWindowIterator itlw (dwProcessId);
for (HWND hwndTopLevelWindow = itlw.First (); hwndTopLevelWindow; hwndTopLevelWindow = itlw.Next())
{
::ShowWindow (hwndTopLevelWindow, SW_MINIMIZE);
}
return 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View file

@ -0,0 +1,34 @@
<HTML>
<HEAD>
<TITLE>Pirates of the Carribean Online</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function PassParameter()
{
DisneyOnlineGames.ModeId=4
DisneyOnlineGames.Token="UserLoggedOnToken"
DisneyOnlineGames.runPiratesOnline();
}
</SCRIPT>
</HEAD>
<BODY>
<center>
<p></p>
<IMG SRC="\\neo\tspool\dev\disney\pirates\online\Workarea/dsnyblst\testActiveX\wwwroot-Example\PiratesSetup.gif">
<object id="DisneyOnlineGames" classid="CLSID:3DCEC959-378A-4922-AD7E-FD5C925D927F" height="0" width="0" codebase="\\neo\tspool\dev\disney\pirates\online\Workarea/dsnyblst\testActiveX\built\signed\DisneyOnlineGames.cab#Version=7,6,6,1549">
</object>
<p></p>
<INPUT TYPE="button" NAME="Install" VALUE="Begin the Adventure" ONCLICK=PassParameter()>
<SCRIPT FOR=DisneyOnlineGames EVENT=onRunPiratesOnlineComplete()>
<!-- {
window.document.write("onRunPiratesOnlineComplete = " + DisneyOnlineGames.ResponseCode)
-->
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,34 @@
<HTML>
<HEAD>
<TITLE>Pirates of the Carribean Online</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function PassParameter()
{
DisneyOnlineGames.ModeId=4
DisneyOnlineGames.Token="UserLoggedOnToken"
DisneyOnlineGames.runPiratesOnline();
}
</SCRIPT>
</HEAD>
<BODY>
<center>
<p></p>
<IMG SRC="http://127.0.0.1/PiratesSetup.gif">
<object id="DisneyOnlineGames" classid="CLSID:3DCEC959-378A-4922-AD7E-FD5C925D927F" height="0" width="0" codebase="http://127.0.0.1/DisneyOnlineGames.cab#Version=7,6,6,1549">
</object>
<p></p>
<INPUT TYPE="button" NAME="Install" VALUE="Begin the Adventure" ONCLICK=PassParameter()>
<SCRIPT FOR=DisneyOnlineGames EVENT=onRunPiratesOnlineComplete()>
<!-- {
window.document.write("onRunPiratesOnlineComplete = " + DisneyOnlineGames.ResponseCode)
-->
</SCRIPT>
</BODY>
</HTML>

View file

@ -0,0 +1,34 @@
<HTML>
<HEAD>
<TITLE>Pirates of the Carribean Online</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function PassParameter()
{
DisneyOnlineGames.ModeId=4
DisneyOnlineGames.Token="UserLoggedOnToken"
DisneyOnlineGames.runPiratesOnline();
}
</SCRIPT>
</HEAD>
<BODY>
<center>
<p></p>
<IMG SRC="http://www.soundmine.com/pirates/PiratesSetup.gif">
<object id="DisneyOnlineGames" classid="CLSID:3DCEC959-378A-4922-AD7E-FD5C925D927F" height="0" width="0" codebase="http://www.soundmine.com/pirates/DisneyOnlineGames.cab#Version=7,6,6,1549">
</object>
<p></p>
<INPUT TYPE="button" NAME="Install" VALUE="Begin the Adventure" ONCLICK=PassParameter()>
<SCRIPT FOR=DisneyOnlineGames EVENT=onRunPiratesOnlineComplete()>
<!-- {
window.document.write("onRunPiratesOnlineComplete = " + DisneyOnlineGames.ResponseCode)
-->
</SCRIPT>
</BODY>
</HTML>

4
otp/src/ai/.cvsignore Normal file
View file

@ -0,0 +1,4 @@
.cvsignore
Makefile
*.pyc
pp.dep

278
otp/src/ai/AIBase.py Normal file
View file

@ -0,0 +1,278 @@
from pandac.PandaModules import *
from direct.directnotify.DirectNotifyGlobal import *
from direct.showbase.MessengerGlobal import *
from direct.showbase.BulletinBoardGlobal import *
from direct.task.TaskManagerGlobal import *
from direct.showbase.JobManagerGlobal import *
from direct.showbase.EventManagerGlobal import *
from direct.showbase.PythonUtil import *
from direct.showbase import PythonUtil
from direct.interval.IntervalManager import ivalMgr
from direct.task import Task
from direct.showbase import EventManager
from direct.showbase import ExceptionVarDump
import math
import sys
import time
import gc
## assert game.process == 'ai', "Are you intentionally running ai code on %s"%(game.process,)
class AIBase:
notify = directNotify.newCategory("AIBase")
def __init__(self):
# Get the dconfig object
self.config = getConfigShowbase()
__builtins__["__dev__"] = self.config.GetBool('want-dev', 0)
if self.config.GetBool('want-variable-dump', 0):
ExceptionVarDump.install()
if self.config.GetBool('use-vfs', 1):
vfs = VirtualFileSystem.getGlobalPtr()
else:
vfs = None
# Store dconfig variables
self.wantTk = self.config.GetBool('want-tk', 0)
# How long should the AI sleep between frames to keep CPU usage down
self.AISleep = self.config.GetFloat('ai-sleep', 0.04)
self.AIRunningNetYield = self.config.GetBool('ai-running-net-yield', 0)
self.AIForceSleep = self.config.GetBool('ai-force-sleep', 0)
self.eventMgr = eventMgr
self.messenger = messenger
self.bboard = bulletinBoard
self.taskMgr = taskMgr
Task.TaskManager.taskTimerVerbose = self.config.GetBool('task-timer-verbose', 0)
Task.TaskManager.extendedExceptions = self.config.GetBool('extended-exceptions', 0)
self.sfxManagerList = None
self.musicManager = None
self.jobMgr = jobMgr
self.hidden = NodePath('hidden')
# each zone has its own render
#self.render = NodePath('render')
# This graphics engine is not intended to ever draw anything, it
# advanced clocks and clears pstats state, just like on the client.
self.graphicsEngine = GraphicsEngine()
# Get a pointer to Panda's global ClockObject, used for
# synchronizing events between Python and C.
# object is exactly in sync with the TrueClock.
globalClock = ClockObject.getGlobalClock()
# Since we have already started up a TaskManager, and probably
# a number of tasks; and since the TaskManager had to use the
# TrueClock to tell time until this moment, make sure the
# globalClock
self.trueClock = TrueClock.getGlobalPtr()
globalClock.setRealTime(self.trueClock.getShortTime())
# set the amount of time used to compute average frame rate
globalClock.setAverageFrameRateInterval(30.)
globalClock.tick()
# Now we can make the TaskManager start using the new globalClock.
taskMgr.globalClock = globalClock
__builtins__["ostream"] = Notify.out()
__builtins__["globalClock"] = globalClock
__builtins__["vfs"] = vfs
__builtins__["hidden"] = self.hidden
#__builtins__["render"] = self.render
AIBase.notify.info('__dev__ == %s' % __dev__)
# set up recording of Functor creation stacks in __dev__
PythonUtil.recordFunctorCreationStacks()
# This is temporary:
__builtins__["wantTestObject"] = self.config.GetBool('want-test-object', 0)
self.wantStats = self.config.GetBool('want-pstats', 0)
Task.TaskManager.pStatsTasks = self.config.GetBool('pstats-tasks', 0)
# Set up the TaskManager to reset the PStats clock back
# whenever we resume from a pause. This callback function is
# a little hacky, but we can't call it directly from within
# the TaskManager because he doesn't know about PStats (and
# has to run before libpanda is even loaded).
taskMgr.resumeFunc = PStatClient.resumeAfterPause
# in production, we want to use fake textures.
defaultValue = 1
if __dev__:
defaultValue = 0
wantFakeTextures = self.config.GetBool('want-fake-textures-ai',
defaultValue)
if wantFakeTextures:
# Setting textures-header-only is a little better than
# using fake-texture-image. The textures' headers are
# read to check their number of channels, etc., and then a
# 1x1 blue texture is created. It loads quickly, consumes
# very little memory, and doesn't require a bogus texture
# to be loaded repeatedly.
loadPrcFileData('aibase', 'textures-header-only 1')
# If there's a Toontown-specific AIBase, that's where the following
# config flags should be.
# I tried putting this logic in ToontownAIRepository, but wantPets is
# needed during the import of ToontownAIRepository.py
self.wantPets = self.config.GetBool('want-pets', 1)
if self.wantPets:
if game.name == 'toontown':
from toontown.pets import PetConstants
self.petMoodTimescale = self.config.GetFloat(
'pet-mood-timescale', 1.)
self.petMoodDriftPeriod = self.config.GetFloat(
'pet-mood-drift-period', PetConstants.MoodDriftPeriod)
self.petThinkPeriod = self.config.GetFloat(
'pet-think-period', PetConstants.ThinkPeriod)
self.petMovePeriod = self.config.GetFloat(
'pet-move-period', PetConstants.MovePeriod)
self.petPosBroadcastPeriod = self.config.GetFloat(
'pet-pos-broadcast-period',
PetConstants.PosBroadcastPeriod)
self.wantBingo = self.config.GetBool('want-fish-bingo', 1)
self.wantKarts = self.config.GetBool('wantKarts', 1)
self.newDBRequestGen = self.config.GetBool(
'new-database-request-generate', 1)
self.waitShardDelete = self.config.GetBool('wait-shard-delete', 1)
self.blinkTrolley = self.config.GetBool('blink-trolley', 0)
self.fakeDistrictPopulations = self.config.GetBool('fake-district-populations', 0)
self.wantSwitchboard = self.config.GetBool('want-switchboard', 0)
self.wantSwitchboardHacks = self.config.GetBool('want-switchboard-hacks', 0)
self.GEMdemoWhisperRecipientDoid = self.config.GetBool('gem-demo-whisper-recipient-doid', 0)
self.sqlAvailable = self.config.GetBool('sql-available', 1)
self.createStats()
self.restart()
## ok lets over ride the time yieldFunction
#self.MaxEpockSpeed = 1.0/60.0;
#taskMgr.doYield = self.taskManagerDoYield;
def setupCpuAffinities(self, minChannel):
if game.name == 'uberDog':
affinityMask = self.config.GetInt('uberdog-cpu-affinity-mask', -1)
else:
affinityMask = self.config.GetInt('ai-cpu-affinity-mask', -1)
if affinityMask != -1:
TrueClock.getGlobalPtr().setCpuAffinity(affinityMask)
else:
# this is useful on machines that perform better with each process
# assigned to a single CPU
autoAffinity = self.config.GetBool('auto-single-cpu-affinity', 0)
if game.name == 'uberDog':
affinity = self.config.GetInt('uberdog-cpu-affinity', -1)
if autoAffinity and (affinity == -1):
affinity = 2
else:
affinity = self.config.GetInt('ai-cpu-affinity', -1)
if autoAffinity and (affinity == -1):
affinity = 1
if affinity != -1:
TrueClock.getGlobalPtr().setCpuAffinity(1 << affinity)
elif autoAffinity:
if game.name == 'uberDog':
# set the affinity based on our channel range
channelSet = int(minChannel / 1000000)
channelSet -= 240
# add an offset so that the default uberdog affinity is 2
affinity = channelSet + 3
# this could be better if we know how many CPUs we have
# for now spread the uberdogs across 4 processors
TrueClock.getGlobalPtr().setCpuAffinity(1 << (affinity % 4))
#########################################################################
# This is the yield function for simple timing based .. no consideration for Network and such..
###########################################################################
def taskManagerDoYield(self , frameStartTime, nextScheuledTaksTime):
minFinTime = frameStartTime + self.MaxEpockSpeed
if nextScheuledTaksTime > 0 and nextScheuledTaksTime < minFinTime:
minFinTime = nextScheuledTaksTime;
delta = minFinTime - globalClock.getRealTime();
while(delta > 0.002):
time.sleep(delta)
delta = minFinTime - globalClock.getRealTime();
def createStats(self, hostname=None, port=None):
# You can specify pstats-host in your Config.prc or use ~pstats/~aipstats
# The default is localhost
if not self.wantStats:
return False
if PStatClient.isConnected():
PStatClient.disconnect()
# these default values match the C++ default values
if hostname is None:
hostname = ''
if port is None:
port = -1
PStatClient.connect(hostname, port)
return PStatClient.isConnected()
def __sleepCycleTask(self, task):
# To keep the AI task from running too fast, we sleep a bit here
time.sleep(self.AISleep)
return Task.cont
def __resetPrevTransform(self, state):
# Clear out the previous velocity deltas now, after we have
# rendered (the previous frame). We do this after the render,
# so that we have a chance to draw a representation of spheres
# along with their velocities. At the beginning of the frame
# really means after the command prompt, which allows the user
# to interactively query these deltas meaningfully.
PandaNode.resetAllPrevTransform()
return Task.cont
def __ivalLoop(self, state):
# Execute all intervals in the global ivalMgr.
ivalMgr.step()
return Task.cont
def __igLoop(self, state):
# This advances the clocks and clears pstats state
self.graphicsEngine.renderFrame()
return Task.cont
def shutdown(self):
self.taskMgr.remove('ivalLoop')
self.taskMgr.remove('igLoop')
self.taskMgr.remove('aiSleep')
self.eventMgr.shutdown()
def restart(self):
self.shutdown()
# __resetPrevTransform goes at the very beginning of the frame.
self.taskMgr.add(
self.__resetPrevTransform, 'resetPrevTransform', priority = -51)
# spawn the ivalLoop with a later priority, so that it will
# run after most tasks, but before igLoop.
self.taskMgr.add(self.__ivalLoop, 'ivalLoop', priority = 20)
self.taskMgr.add(self.__igLoop, 'igLoop', priority = 50)
if self.AISleep >= 0 and (not self.AIRunningNetYield or self.AIForceSleep):
self.taskMgr.add(self.__sleepCycleTask, 'aiSleep', priority = 55)
self.eventMgr.restart()
def getRepository(self):
return self.air
def run(self):
self.taskMgr.run()

View file

@ -0,0 +1,44 @@
"""instantiate global ShowBase object"""
from AIBase import *
# guard against AI files being imported on the client
assert game.process != 'client'
__builtins__["simbase"] = AIBase()
# Make some global aliases for convenience
__builtins__["ostream"] = Notify.out()
__builtins__["run"] = simbase.run
__builtins__["taskMgr"] = simbase.taskMgr
__builtins__["jobMgr"] = simbase.jobMgr
__builtins__["eventMgr"] = simbase.eventMgr
__builtins__["messenger"] = simbase.messenger
__builtins__["bboard"] = simbase.bboard
__builtins__["config"] = simbase.config
__builtins__["directNotify"] = directNotify
# we don't use ToontownLoader because it just adds progress bar
# functionality to Loader
from direct.showbase import Loader
simbase.loader = Loader.Loader(simbase)
__builtins__["loader"] = simbase.loader
# Set direct notify categories now that we have config
directNotify.setDconfigLevels()
def inspect(anObject):
from direct.tkpanels import Inspector
Inspector.inspect(anObject)
__builtins__["inspect"] = inspect
# this also appears in ShowBaseGlobal
if (not __debug__) and __dev__:
notify = directNotify.newCategory('ShowBaseGlobal')
notify.error("You must set 'want-dev' to false in non-debug mode.")
# Now the builtins are filled in.
taskMgr.finalInit()

483
otp/src/ai/AIDistrict.py Normal file
View file

@ -0,0 +1,483 @@
from pandac.PandaModules import *
from otp.otpbase import OTPGlobals
from AIMsgTypes import *
from direct.showbase.PythonUtil import Functor, randUint32
from direct.directnotify import DirectNotifyGlobal
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.task import Task
from direct.distributed import ParentMgr
from otp.ai.AIRepository import AIRepository
from otp.ai.AIZoneData import AIZoneData, AIZoneDataStore
import sys
import os
import copy
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
if __debug__:
import pdb
class AIDistrict(AIRepository):
notify = DirectNotifyGlobal.directNotify.newCategory("AIDistrict")
def __init__(
self, mdip, mdport, esip, esport, dcFileNames,
districtId, districtName, districtType, serverId,
minChannel, maxChannel, dcSuffix = 'AI'):
assert self.notify.debugStateCall(self)
# Save the district Id (needed for calculations in AIRepository code)
self.districtId = districtId
self.districtName = districtName
self.districtType = districtType
AIRepository.__init__(
self, mdip, mdport, esip, esport, dcFileNames,
serverId,
minChannel, maxChannel, dcSuffix)
self.setClientDatagram(0)
assert minChannel > districtId
if hasattr(self, 'setVerbose'):
if self.config.GetBool('verbose-airepository'):
self.setVerbose(1)
# Save the state server id
self.serverId = serverId
# Record the reason each client leaves the shard, according to
# the client.
self._avatarDisconnectReasons = {}
# A list of avIds to pretend to disconnect at the next poll
# cycle, for debugging purposes only.
self._debugDisconnectIds = []
# player avatars will increment and decrement this count
self._population = 0
# The AI State machine
self.fsm = ClassicFSM.ClassicFSM('AIDistrict',
[State.State('off',
self.enterOff,
self.exitOff,
['connect']),
State.State('connect',
self.enterConnect,
self.exitConnect,
['districtReset', 'noConnection',
# I added this because Skyler removed the transition to
# districtReset -- Joe
'playGame',
]),
State.State('districtReset',
self.enterDistrictReset,
self.exitDistrictReset,
['playGame','noConnection']),
State.State('playGame',
self.enterPlayGame,
self.exitPlayGame,
['noConnection']),
State.State('noConnection',
self.enterNoConnection,
self.exitNoConnection,
['connect'])],
# initial state
'off',
# final state
'off',
)
self.fsm.enterInitialState()
self.fsm.request("connect")
def uniqueName(self, desc):
return desc+"-"+str(self.districtId)
def getGameDoId(self):
self.notify.error('derived must override')
def incrementPopulation(self):
self._population += 1
def decrementPopulation(self):
if __dev__:
assert self._population > 0
self._population = max(0, self._population - 1)
def getPopulation(self):
if simbase.fakeDistrictPopulations:
if not hasattr(self, '_fakePopulation'):
import random
self._fakePopulation = random.randrange(1000)
return self._fakePopulation
return self._population
def printPopulationToLog(self, task):
self.notify.info("district-name %s | district-id %s | population %s" % (self.districtName, self.districtId, self._population))
return Task.again
# check if this is a player avatar in a location where they should not be
def _isValidPlayerLocation(self, parentId, zoneId):
return True
#### Init ####
def writeServerEvent(self, eventType, who, description):
AIRepository.writeServerEvent(self, eventType, who, description,
serverId=self.districtId)
#### DistrictReset ####
def enterDistrictReset(self):
self.handler = self.handleDistrictReset
self.deleteDistrict(self.districtId)
def exitDistrictReset(self):
self.handler = None
def handleDistrictReset(self, msgType, di):
if msgType == STATESERVER_OBJECT_DELETE_RAM:
doId = di.getUint32()
self.notify.info("Got request to delete doId: " +str(doId))
if(doId == self.districtId):
self.fsm.request("playGame")
elif msgType == STATESERVER_OBJECT_NOTFOUND:
doId = di.getUint32()
self.notify.info("Got Not Found For doId: " +str(doId))
if(doId == self.districtId):
self.fsm.request("playGame")
else:
self.handleMessageType(msgType, di)
#### DistrictReset ####
def enterPlayGame(self):
self._zoneDataStore = AIZoneDataStore()
AIRepository.enterPlayGame(self)
if simbase.config.GetBool('game-server-tests', 0):
from otp.distributed import DistributedTestObjectAI
self.testObject = DistributedTestObjectAI.DistributedTestObjectAI(self)
self.testObject.generateOtpObject(self.getGameDoId(), 3)
taskMgr.doMethodLater(300, self.printPopulationToLog, self.uniqueName("printPopulationTask"))
def getZoneDataStore(self):
"""This will crash (as designed) if called outside of the PlayGame state."""
return self._zoneDataStore
def getRender(self, parentId, zoneId):
# distributed objects should call getRender on themselves rather than
# call this function. Only call this for zones that are actively being
# used, otherwise the zone data will be destroyed before this function
# returns
zd = AIZoneData(self, parentId, zoneId)
render = zd.getRender()
zd.destroy()
return render
def getNonCollidableParent(self, parentId, zoneId):
# distributed objects should call getNonCollidableParent on themselves rather than
# call this function. Only call this for zones that are actively being
# used, otherwise the zone data will be destroyed before this function
# returns
zd = AIZoneData(self, parentId, zoneId)
ncParent = zd.getNonCollidableParent()
zd.destroy()
return ncParent
def getCollTrav(self, parentId, zoneId, *args, **kArgs):
# see comment in getRender
zd = AIZoneData(self, parentId, zoneId)
collTrav = zd.getCollTrav(*args, **kArgs)
zd.destroy()
return collTrav
def getParentMgr(self, parentId, zoneId):
# see comment in getRender
zd = AIZoneData(self, parentId, zoneId)
parentMgr = zd.getParentMgr()
zd.destroy()
return parentMgr
def exitPlayGame(self):
if simbase.config.GetBool('game-server-tests', 0):
self.testObject.requestDelete()
del self.testObject
self._zoneDataStore.destroy()
del self._zoneDataStore
taskMgr.remove(self.uniqueName("printPopulationTask"))
AIRepository.exitPlayGame(self)
#### connect #####
def enterConnect(self):
self.handler = self.handleConnect
self.lastMessageTime = 0
self.connect([self.mdurl],
successCallback = self._connected,
failureCallback = self._failedToConnect)
def _failedToConnect(self, statusCode, statusString):
self.fsm.request("noConnection")
def _connected(self):
# Register our channel
self.setConnectionName(self.districtName)
AIRepository._connected(self)
self.registerShardDownMessage(self.serverId)
if self.districtType is not None:
self.fsm.request("districtReset")
def _handleValidDistrictDown(self, msgType, di):
downDistrictId = di.getUint32()
if (downDistrictId != self.districtId):
self.notify.error("Tried to bring down " +
str(self.districtId) +
" but " +
str(downDistrictId) +
" came down instead!")
else:
# We don't really need to do anything here.
pass
def _handleIgnorableObjectDelete(self, msgType, di):
doId = di.getUint32()
self.notify.debug("Ignoring request to delete doId: " +
str(doId))
def _handleValidDistrictUp(self, msgType, di):
if msgType == STATESERVER_DISTRICT_UP:
upDistrictId = di.getUint32()
if (upDistrictId != self.districtId):
self.notify.error("Tried to bring up " +
str(self.districtId) +
" but " +
str(downDistrictId) +
" came up instead!")
else:
self.notify.info("District %s %s is up. Creating objects..." %
(self.districtId, self.districtName))
self.fsm.request("playGame")
def exitConnect(self):
self.handler = None
# Clean up the create district tasks
taskMgr.remove(self.uniqueName("newDistrictWait"))
del self.lastMessageTime
def readerPollUntilEmpty(self, task):
# This overrides AIRepository.readerPollUntilEmpty()
# to provide an additional debugging hook.
while self._debugDisconnectIds:
avId = self._debugDisconnectIds.pop()
self._doDebugDisconnectAvatar(avId)
try:
return AIRepository.readerPollUntilEmpty(self, task)
except Exception, e:
appendStr(e, '\nSENDER ID: %s' % self.getAvatarIdFromSender())
raise
def handleReaderOverflow(self):
# may as well delete the shard at this point
self.deleteDistrict(self.districtId)
raise StandardError, ("incoming-datagram buffer overflowed, "
"aborting AI process")
##### General Purpose functions #####
def getAvatarExitEvent(self, avId):
return ("districtExit-" + str(avId))
def debugDisconnectAvatar(self, avId):
# This function will pretend to disconnect the indicated
# avatar at the next poll cycle, as if the avatar suddenly
# disconnected. This is for the purposes of debugging only.
# It makes the AI totally forget who this avatar is, but the
# avatar is still connected to the server.
self._debugDisconnectIds.append(avId)
def _doDebugDisconnectAvatar(self, avId):
obj = self.doId2do.get(avId)
if obj:
self.deleteDistObject(obj)
self._announceDistObjExit(avId)
def _announceDistObjExit(self, avId):
# This announces the exiting of this particular avatar
messenger.send(self.getAvatarExitEvent(avId))
# This announces generally that an avatar has left.
#messenger.send("avatarExited")
# Now we don't need to store the disconnect reason any more.
try:
del self._avatarDisconnectReasons[avId]
except:
pass
def setAvatarDisconnectReason(self, avId, disconnectReason):
# This is told us by the client just before he disconnects.
self._avatarDisconnectReasons[avId] = disconnectReason
def getAvatarDisconnectReason(self, avId):
# Returns the reason (as reported by the client) for an
# avatar's unexpected exit, or 0 if the reason is unknown. It
# is only valid to query this during the handler for the
# avatar's unexpected-exit event.
return self._avatarDisconnectReasons.get(avId, 0)
def _handleUnexpectedDistrictDown(self, di):
# Get the district Id
downDistrict = di.getUint32()
if downDistrict == self.districtId:
self.notify.warning("Somebody brought my district(" +
str(self.districtId) +
") down! I'm shutting down!")
sys.exit()
else:
self.notify.warning("Weird... My district is " +
str(self.districtId) +
" and I just got a message that district " +
str(downDistrict) +
" is going down. I'm ignoring it."
)
def _handleUnexpectedDistrictUp(self, di):
# Get the district Id
upDistrict = di.getUint32()
if upDistrict == self.districtId:
self.notify.warning("Somebody brought my district(" +
str(self.districtId) +
") up! I'm shutting down!")
sys.exit()
else:
self.notify.warning("Weird... My district is " +
str(self.districtId) +
" and I just got a message that district " +
str(upDistrict) +
" is coming up. I'm ignoring it."
)
def _handleMakeFriendsReply(self, di):
result = di.getUint8()
context = di.getUint32()
messenger.send("makeFriendsReply", [result, context])
def _handleRequestSecretReply(self, di):
result = di.getUint8()
secret = di.getString()
requesterId = di.getUint32()
messenger.send("requestSecretReply", [result, secret, requesterId])
def _handleSubmitSecretReply(self, di):
result = di.getUint8()
secret = di.getString()
requesterId = di.getUint32()
avId = di.getUint32()
self.writeServerEvent('entered-secret', requesterId, '%s|%s|%s' % (result, secret, avId))
messenger.send("submitSecretReply", [result, secret, requesterId, avId])
def registerShardDownMessage(self, stateserverid):
datagram = PyDatagram()
datagram.addServerHeader(
stateserverid, self.ourChannel, STATESERVER_SHARD_REST)
datagram.addChannel(self.ourChannel)
# schedule for execution on socket close
self.addPostSocketClose(datagram)
def sendSetZone(self, distobj, zoneId):
datagram = PyDatagram()
datagram.addServerHeader(
distobj.doId, self.ourChannel, STATESERVER_OBJECT_SET_ZONE)
# Add the zone parent id
# HACK:
parentId = oldParentId = self.districtId
datagram.addUint32(parentId)
# Put in the zone id
datagram.addUint32(zoneId)
# Send it
self.send(datagram)
# The servers don't inform us of this zone change, because we're the
# one that requested it. Update immediately.
# TODO: pass in the old parent and old zone
distobj.setLocation(parentId, zoneId) #, oldParentId, distobj.zoneId)
def deleteDistrict(self, districtId):
# Create a message
datagram = PyDatagram()
datagram.addServerHeader(
self.serverId, self.ourChannel, STATESERVER_OBJECT_DELETE_RAM)
# The Id of the object in question
datagram.addUint32(districtId)
# Send the message
self.send(datagram)
# Make sure the message gets there.
self.flush()
def makeFriends(self, avatarAId, avatarBId, flags, context):
"""
Requests to make a friendship between avatarA and avatarB with
the indicated flags (or upgrade an existing friendship with
the indicated flags). The context is any arbitrary 32-bit
integer. When the friendship is made, or the operation fails,
the "makeFriendsReply" event is generated, with two
parameters: an integer result code, and the supplied context.
"""
datagram = PyDatagram()
datagram.addServerHeader(
DBSERVER_ID, self.ourChannel, DBSERVER_MAKE_FRIENDS)
# Indicate the two avatars who are making friends
datagram.addUint32(avatarAId)
datagram.addUint32(avatarBId)
datagram.addUint8(flags)
datagram.addUint32(context)
self.send(datagram)
def requestSecret(self, requesterId):
"""
Requests a "secret" from the database server. This is a
unique string that will be associated with the indicated
requesterId, for the purposes of authenticating true-life
friends.
When the secret is ready, a "requestSecretReply" message will
be thrown with three parameters: the result code (0 or 1,
indicating failure or success), the generated secret, and the
requesterId again.
"""
datagram = PyDatagram()
datagram.addServerHeader(
DBSERVER_ID,self.ourChannel,DBSERVER_REQUEST_SECRET)
# Indicate the number we want to associate with the new secret.
datagram.addUint32(requesterId)
# Send it off!
self.send(datagram)
def submitSecret(self, requesterId, secret):
"""
Submits a "secret" back to the database server for validation.
This attempts to match the indicated string, entered by the
user, to a string returned by a previous call to
requestSecret().
When the response comes back from the server, a
"submitSecretReply" message will be thrown with four
parameters: the result code (0 or 1, indicating failure or
success), the secret again, the requesterId again, and the
number associated with the original secret (that is, the
original requesterId).
"""
datagram = PyDatagram()
datagram.addServerHeader(
DBSERVER_ID, self.ourChannel, DBSERVER_SUBMIT_SECRET)
# Pass in our identifying number, and the string.
datagram.addUint32(requesterId)
datagram.addString(secret)
self.send(datagram)
def replaceMethod(self, oldMethod, newFunction):
return 0

View file

@ -0,0 +1,19 @@
# AIInterestHandles
#
# These are reserved interest handle id's to be used with calls
# to AIRepository.addInterestToConnection(). The high bit (16th) is set
# on all handle id's assigned by this function call so as not to collide
# with handles assigned by the Client.
# Pirates
PIRATES_CARDGAME = 1
PIRATES_CREW = 2
PIRATES_GUILD = 3
PIRATES_FRIENDS = 4
PIRATES_BAND = 5
PIRATES_PVP_RESPAWN = 6
PIRATES_TREASUREMAP = 7
PIRATES_SHIPPVP = 8

118
otp/src/ai/AIMsgTypes.py Normal file
View file

@ -0,0 +1,118 @@
"""
AIMsgTypes module:
Contains AI specific network message types
"""
from otp.distributed.OtpDoGlobals import *
from direct.showbase.PythonUtil import invertDictLossless
# top level object (root):
OTP_SERVER_ROOT_DO_ID = 4007
CHANNEL_CLIENT_BROADCAST = 4014
BAD_CHANNEL_ID = 0 # 0xffffffffffffffff # -1
BAD_ZONE_ID = 0 # 0xffffffff # -1
BAD_DO_ID = 0 # 0xffffffff # -1
# Control Transactions
CONTROL_MESSAGE = 4001
CONTROL_SET_CHANNEL = 2001
CONTROL_REMOVE_CHANNEL = 2002
CONTROL_SET_CON_NAME = 2004
CONTROL_SET_CON_URL = 2005
CONTROL_ADD_RANGE = 2008
CONTROL_REMOVE_RANGE = 2009
CONTROL_ADD_POST_REMOVE = 2010 # ADD A MESSAGE TO THE CLOSING EVENT ON A DIRECTOR SOCKET
CONTROL_CLEAR_POST_REMOVE = 2011 # CLEAR ALL THE EVENTS..
AIMsgName2Id = {
# State Server Transactions
'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED': 2001,
'STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER': 2003,
'STATESERVER_OBJECT_UPDATE_FIELD': 2004,
'STATESERVER_OBJECT_UPDATE_FIELD_MULTIPLE': 2005,
'STATESERVER_OBJECT_DELETE_RAM': 2007,
'STATESERVER_OBJECT_SET_ZONE': 2008,
'STATESERVER_OBJECT_CHANGE_ZONE': 2009,
'STATESERVER_OBJECT_NOTFOUND': 2015,
'STATESERVER_QUERY_OBJECT_ALL': 2020,
'STATESERVER_QUERY_ZONE_OBJECT_ALL': 2021,
'STATESERVER_OBJECT_LOCATE': 2022,
'STATESERVER_OBJECT_LOCATE_RESP': 2023,
'STATESERVER_OBJECT_QUERY_FIELD': 2024, # See 2062
'STATESERVER_QUERY_OBJECT_ALL_RESP': 2030,
'STATESERVER_SHARD_REST': 2061,
'STATESERVER_ADD_AI_RECV': 2045,
'STATESERVER_QUERY_ZONE_OBJECT_ALL_DONE': 2046,
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT': 2050,
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT': 2051,
'STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT_RESP': 2052,
'STATESERVER_OBJECT_CREATE_WITH_REQUIR_OTHER_CONTEXT_RESP': 2053,
'STATESERVER_OBJECT_DELETE_DISK': 2060,
'STATESERVER_OBJECT_QUERY_FIELD_RESP': 2062, # See 2024
'STATESERVER_OBJECT_ENTERZONE_WITH_REQUIRED_OTHER': 2066,
'STATESERVER_OBJECT_ENTER_AI_RECV': 2067,
'STATESERVER_OBJECT_LEAVING_AI_INTEREST': 2033, # This is the new name for 2033
'STATESERVER_OBJECT_ENTER_OWNER_RECV': 2068, # new obj with owner
'STATESERVER_OBJECT_CHANGE_OWNER_RECV': 2069, # obj has new owner
'STATESERVER_OBJECT_SET_OWNER_RECV': 2070, # ???
'STATESERVER_OBJECT_QUERY_FIELDS': 2080,
'STATESERVER_OBJECT_QUERY_FIELDS_RESP': 2081,
'STATESERVER_OBJECT_QUERY_FIELDS_STRING': 2082,
'STATESERVER_OBJECT_QUERY_MANAGING_AI': 2083, # Should not be received by python code (it's for roger's server)
'STATESERVER_BOUNCE_MESSAGE': 2086,
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL': 2087,
'STATESERVER_QUERY_OBJECT_CHILDREN_LOCAL_DONE': 2089,
'STATESERVER_QUERY_OBJECT_CHILDREN_RESP': 2087,
'ACCOUNT_AVATAR_USAGE': 3005, # Avatar online or offline
'ACCOUNT_ACCOUNT_USAGE': 3006, # Account login or log off
'CLIENT_AGENT_OPEN_CHANNEL': 3104,
'CLIENT_AGENT_CLOSE_CHANNEL': 3105,
'CLIENT_AGENT_SET_INTEREST': 3106,
'CLIENT_AGENT_REMOVE_INTEREST': 3107,
'CHANNEL_PUPPET_ACTION': 4004, # Account and Avatar online or offline
# direct-to-database-server transactions
'DBSERVER_MAKE_FRIENDS': 1017,
'DBSERVER_MAKE_FRIENDS_RESP': 1031,
'DBSERVER_REQUEST_SECRET': 1025,
'DBSERVER_REQUEST_SECRET_RESP': 1026,
'DBSERVER_SUBMIT_SECRET': 1027,
'DBSERVER_SUBMIT_SECRET_RESP': 1028,
'DBSERVER_CREATE_STORED_OBJECT': 1003,
'DBSERVER_CREATE_STORED_OBJECT_RESP': 1004,
'DBSERVER_DELETE_STORED_OBJECT': 1008,
'DBSERVER_GET_STORED_VALUES': 1012,
'DBSERVER_GET_STORED_VALUES_RESP': 1013,
'DBSERVER_SET_STORED_VALUES': 1014,
'SERVER_PING': 5002,
}
# create id->name table for debugging
AIMsgId2Names = invertDictLossless(AIMsgName2Id)
# put msg names in module scope, assigned to msg value
for name, value in AIMsgName2Id.items():
exec '%s = %s' % (name, value)
del name, value
# The ID number of the database server. The above direct-to-dbserver
# transactions are sent to this ID.
DBSERVER_ID = 4003

1913
otp/src/ai/AIRepository.py Normal file

File diff suppressed because it is too large Load diff

245
otp/src/ai/AIZoneData.py Normal file
View file

@ -0,0 +1,245 @@
from pandac.PandaModules import *
from direct.distributed import ParentMgr
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.task import Task
from direct.showbase import LeakDetectors
from otp.otpbase import OTPGlobals
import random
class AIZoneData:
"""This is a proxy to the AIZoneDataObj for a particular zone. When all
AIZoneData objects for a zone have been destroyed, the AIZoneDataObj
object for that zone is destroyed as well."""
notify = directNotify.newCategory('AIZoneData')
def __init__(self, air, parentId, zoneId):
self._air = air
self._parentId = parentId
self._zoneId = zoneId
self._data = self._air.getZoneDataStore().getDataForZone(self._parentId, self._zoneId)
def destroy(self):
del self._data
self._air.getZoneDataStore().releaseDataForZone(self._parentId, self._zoneId)
del self._zoneId
del self._parentId
del self._air
def __getattr__(self, attr):
# provide direct access to AIZoneDataStore methods on this object
return getattr(self._data, attr)
class AIZoneDataObj:
"""
This class stores per-zone information on an AI district. Only one of these
exists for a particular zone, and it only exists if somebody requested it.
"""
notify = directNotify.newCategory('AIZoneDataObj')
DefaultCTravName = 'default'
def __init__(self, parentId, zoneId):
assert self.notify.debug(
'AIZoneDataObj.__init__(%s, %s)' % (parentId, zoneId))
self._parentId = parentId
self._zoneId = zoneId
self._refCount = 0
self._collTravs = {}
self._collTravsStarted = set()
def __str__(self):
output = str(self._collTravs)
output += '\n'
totalColliders = 0
totalTraversers = 0
for currCollTrav in self._collTravs.values():
totalTraversers += 1
totalColliders += currCollTrav.getNumColliders()
output += 'Num traversers: %s Num total colliders: %s'%(totalTraversers,totalColliders)
return output
def _incRefCount(self):
self._refCount += 1
def _decRefCount(self):
self._refCount -= 1
def _getRefCount(self):
return self._refCount
def destroy(self):
assert self.notify.debug(
'AIZoneDataObj.destroy(%s, %s)' % (self._parentId, self._zoneId))
for name in list(self._collTravsStarted):
self.stopCollTrav(cTravName=name)
del self._collTravsStarted
del self._collTravs
if hasattr(self, '_nonCollidableParent'):
self._nonCollidableParent.removeNode()
del self._nonCollidableParent
if hasattr(self, '_render'):
if hasattr(self, '_renderLeakDetector'):
self._renderLeakDetector.destroy()
del self._renderLeakDetector
self._render.removeNode()
del self._render
if hasattr(self, '_parentMgr'):
self._parentMgr.destroy()
del self._parentMgr
del self._zoneId
del self._parentId
def getLocation(self):
return self._parentId, self._zoneId
def getRender(self):
if not hasattr(self, '_render'):
self._render = NodePath('render-%s-%s' % (self._parentId, self._zoneId))
if config.GetBool('leak-scene-graph', 0):
self._renderLeakDetector = LeakDetectors.SceneGraphLeakDetector(self._render)
return self._render
def getNonCollidableParent(self):
# this is a node for things that can't be collided against, so that that collision traverser
# only has to check once against this node. It's up to the show code to make sure that
# no collidables are put under this node
if not hasattr(self, '_nonCollidableParent'):
render = self.getRender()
self._nonCollidableParent = render.attachNewNode('nonCollidables')
if __dev__:
assert self._nonCollidableParent.getCollideMask() == BitMask32().allOff(),\
"collidable geometry under non-collidable parent node for location "\
"(%s,%s)" % (self._parentId, self._zoneId)
return self._nonCollidableParent
def getParentMgr(self):
if not hasattr(self, '_parentMgr'):
self._parentMgr = ParentMgr.ParentMgr()
self._parentMgr.registerParent(OTPGlobals.SPHidden, hidden)
self._parentMgr.registerParent(OTPGlobals.SPRender, self.getRender())
return self._parentMgr
def hasCollTrav(self, name=None):
if name is None:
name = AIZoneDataObj.DefaultCTravName
return name in self._collTravs
def getCollTrav(self, name=None):
#assert self.notify.debug('getCollTrav(%s, %s)' % (self._parentId, self._zoneId))
if name is None:
name = AIZoneDataObj.DefaultCTravName
if name not in self._collTravs:
self._collTravs[name] = CollisionTraverser('cTrav-%s-%s-%s' % (name, self._parentId, self._zoneId))
return self._collTravs[name]
def removeCollTrav(self, name):
if (self._collTravs.has_key(name)):
del self._collTravs[name]
def _getCTravTaskName(self, name=None):
if name is None:
name = AIZoneDataObj.DefaultCTravName
return 'collTrav-%s-%s-%s' % (name, self._parentId, self._zoneId)
def _doCollisions(self, task=None, topNode=None, cTravName=None):
render = self.getRender()
curTime = globalClock.getFrameTime()
render.setTag('lastTraverseTime', str(curTime))
if topNode is not None:
# make sure the topNode for collision traversal is a descendant of our render node
if not render.isAncestorOf(topNode):
self.notify.warning('invalid topNode for collision traversal in %s: %s' % (
self.getLocation(), topNode))
else:
topNode = render
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
collTrav = self._collTravs[cTravName]
messenger.send('preColl-' + collTrav.getName())
collTrav.traverse(topNode)
messenger.send('postColl-' + collTrav.getName())
return Task.cont
def doCollTrav(self, topNode=None, cTravName=None):
# call this method to do a one-shot collision traversal (instead of starting up a task
# to traverse every frame)
assert self.notify.debug('doCollTrav(%s, %s)' % (self._parentId, self._zoneId))
self.getCollTrav(cTravName)
self._doCollisions(topNode=topNode, cTravName=cTravName)
def startCollTrav(self, respectPrevTransform=1, cTravName=None):
"""sets up and starts collision traverser for this zone.
Pass in zero for 'respectPrevTransform' to disable support for
tunneling/trailing sphere support. This will allow objects to
break through collision barriers, but may run faster -- see
drose for more info.
"""
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
assert self.notify.debug(
'startCollTrav(%s, (%s, %s), %s)' % (cTravName, self._parentId, self._zoneId, respectPrevTransform))
if not cTravName in self._collTravsStarted:
# make sure we've got a collision traverser
self.getCollTrav(name=cTravName)
taskMgr.add(self._doCollisions, self._getCTravTaskName(name=cTravName),
priority=OTPGlobals.AICollisionPriority,
extraArgs=[self._zoneId])
self._collTravsStarted.add(cTravName)
assert self.notify.debug(
'adding %s collision traversal for (%s, %s)' % (cTravName, self._parentId, self._zoneId))
self.setRespectPrevTransform(respectPrevTransform, cTravName=cTravName)
def stopCollTrav(self, cTravName=None):
"""frees resources used by collision traverser for this zone"""
assert self.notify.debugStateCall(self)
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
self.notify.debug('stopCollTrav(%s, %s, %s)' % (cTravName, self._parentId, self._zoneId))
if cTravName in self._collTravsStarted:
self.notify.info(
'removing %s collision traversal for (%s, %s)' % (cTravName, self._parentId, self._zoneId))
taskMgr.remove(self._getCTravTaskName(name=cTravName))
self._collTravsStarted.remove(cTravName)
def setRespectPrevTransform(self, flag, cTravName=None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
self._collTravs[cTravName].setRespectPrevTransform(flag)
def getRespectPrevTransform(self, cTravName=None):
if cTravName is None:
cTravName = AIZoneDataObj.DefaultCTravName
return self._collTravs[cTravName].getRespectPrevTransform()
class AIZoneDataStore:
"""This class holds all of the AIZoneDataObj objects for a district."""
notify = directNotify.newCategory('AIZoneDataStore')
def __init__(self):
# table of (parentId, zoneId) -> AIZoneDataObj
self._zone2data = {}
def destroy(self):
for zone, data in self._zone2data.items():
data.destroy()
del self._zone2data
def hasDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
return key in self._zone2data
def getDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
if key not in self._zone2data:
self._zone2data[key] = AIZoneDataObj(parentId, zoneId)
self.printStats()
data = self._zone2data[key]
data._incRefCount()
return data
def releaseDataForZone(self, parentId, zoneId):
key = (parentId, zoneId)
data = self._zone2data[key]
data._decRefCount()
refCount = data._getRefCount()
assert (refCount >= 0)
if refCount == 0:
del self._zone2data[key]
data.destroy()
self.printStats()
def printStats(self):
self.notify.debug('%s zones have zone data allocated' % len(self._zone2data))

View file

@ -0,0 +1,97 @@
#################################################################
# File: BanManagerAI.py
# Purpose: Module to ban avatars while inside the game and kick
# them out of the game
#################################################################
import urllib
import os
from pandac.PandaModules import HTTPClient, Ramfile
from direct.directnotify import DirectNotifyGlobal
class BanManagerAI:
notify = DirectNotifyGlobal.directNotify.newCategory("BanManagerAI")
# These URLS came from Alper Akture
# dev instance (but as of 7/1/2010 hooked to live disl)
# http://dnhdosapp01.wdig.com:8005/dis-hold/action/event
# qa instance
# http://qnhspapp02.wdig.com:8005/dis-hold/action/event
# live
# https://vapps.disl.starwave.com:8005/dis-hold/action/event
BanUrl = simbase.config.GetString("ban-base-url", "https://vapps.disl.starwave.com:8005/dis-hold/action/event")
App = simbase.config.GetString("ban-app-name", "TTWorldAI")
Product = simbase.config.GetString("ban-product", "Toontown")
EventName = simbase.config.GetString("ban-event-name", "tthackattempt")
def __init__(self):
"""Construct and initialize members."""
self.curBanRequestNum = 0
self.channels = {}
self.ramFiles = {}
def ban(self, avatarId, dislid, comment):
"""Ban the player"""
parameters = ""
parameters += "app=%s" % self.App
parameters += "&product=%s" % self.Product
parameters += "&user_id=%s" % dislid
parameters += "&event_name=%s" % self.EventName
commentWithAvatarId = "avId-%s " % avatarId
commentWithAvatarId += comment
parameters += "&comments=%s" % urllib.quote(str(commentWithAvatarId))
# get the base ban url from the environment variable first
baseUrlToUse = self.BanUrl
osBaseUrl = os.getenv("BAN_URL")
if osBaseUrl:
baseUrlToUse = osBaseUrl
fullUrl = baseUrlToUse + "?" + parameters
self.notify.info ("ban request %s dislid=%s comment=%s fullUrl=%s" % (self.curBanRequestNum, dislid, comment, fullUrl))
simbase.air.writeServerEvent('ban_request', avatarId, "%s|%s|%s" % (dislid, comment, fullUrl))
if simbase.config.GetBool('do-actual-ban',False):
newTaskName = "ban-task-%d" % self.curBanRequestNum
newTask = taskMgr.add(self.doBanUrlTask, newTaskName)
newTask.banRequestNum = self.curBanRequestNum
http = HTTPClient.getGlobalPtr()
channel = http.makeChannel(False) # hmm should we make true for a persistent connection?
self.channels [ self.curBanRequestNum] = channel
rf = Ramfile()
self.ramFiles [ self.curBanRequestNum] = rf
channel.beginGetDocument(fullUrl)
channel.downloadToRam(rf)
self.curBanRequestNum += 1
def cleanupBanReq(self, banReq):
"""Cleanup stuff that's associated with this ban request."""
channel = self.channels.get(banReq)
if channel:
del self.channels[banReq]
ramfile = self.ramFiles.get(banReq)
if ramfile:
del self.ramFiles[banReq]
def doBanUrlTask(self, task):
"""Continue downloading the ban url if needed."""
banReq = task.banRequestNum
channel = self.channels.get(banReq)
if channel:
if channel.run():
return task.cont
else:
self.notify.warning("no channel for ban req %s" % banReq)
self.cleanupBanReq(banReq)
return task.done
result = ""
ramfile = self.ramFiles.get(banReq)
if ramfile:
result = ramfile.getData()
self.notify.info("done processing ban request %s, ramFile=%s" % (banReq, result))
self.cleanupBanReq(banReq)
return task.done

138
otp/src/ai/Barrier.py Normal file
View file

@ -0,0 +1,138 @@
""" Barrier.py: contains the Barrier class: utility class for AI objects that must wait for a message from each of a list of Avatars """
from otp.ai.AIBase import *
from direct.task import Task
from direct.showbase import DirectObject
import random
class Barrier(DirectObject.DirectObject):
notify = directNotify.newCategory('Barrier')
def __init__(self, name, uniqueName, avIdList, timeout,
clearedFunc = None, timeoutFunc = None,
doneFunc = None):
"""
name: a context name that should be used in common with the
client code.
uniqueName: should be a unique name for this Barrier, used
for timeout doLater
avIdList: list of avatars from which we'll expect responses
timeout: how long to wait before giving up
clearedFunc: func to call when all avatars have cleared the barrier;
takes no arguments
timeoutFunc: func to call when the timeout has expired;
takes list of avIds of avatars that did not
clear the barrier
doneFunc: func to call when the the barrier is complete for
either reason; takes list of avIds of avatars that
successfully cleared the barrier
Call Barrier.clear(avId) when you get a response from
each avatar.
If you need to have additional parameters passed to your
callback funcs, see PythonUtil.Functor
"""
self.name = name
self.uniqueName = uniqueName + '-Barrier'
self.avIdList = avIdList[:]
self.pendingAvatars = self.avIdList[:]
self.timeout = timeout
self.clearedFunc = clearedFunc
self.timeoutFunc = timeoutFunc
self.doneFunc = doneFunc
if len(self.pendingAvatars) == 0:
# If we are initialized with an empty list of avatars to
# wait for, we consider ourselves cleared immediately.
self.notify.debug(
'%s: barrier with empty list' % (self.uniqueName))
self.active = 0
if self.clearedFunc:
self.clearedFunc()
if self.doneFunc:
self.doneFunc(self.avIdList)
return
# choose a name for the timeout task
self.taskName = self.uniqueName + '-Timeout'
# this shouldn't be necessary, and it's kind of ugly;
# in any case, it's better than bringing down the AI server
# with an assert
origTaskName = self.taskName
while taskMgr.hasTaskNamed(self.taskName):
self.taskName = origTaskName + '-' + str(random.randint(0, 10000))
# start the timeout
taskMgr.doMethodLater(self.timeout,
self.__timerExpired,
self.taskName)
# Hang hooks for each avatar to disappear.
for avId in self.avIdList:
event = simbase.air.getAvatarExitEvent(avId)
self.acceptOnce(event, self.__handleUnexpectedExit, extraArgs=[avId])
self.notify.debug(
'%s: expecting responses from %s within %s seconds' %
(self.uniqueName, self.avIdList, self.timeout))
self.active = 1
def cleanup(self):
"""
call this if you're abandoning the barrier condition and
discarding this object
"""
if self.active:
taskMgr.remove(self.taskName)
self.active = 0
self.ignoreAll()
def clear(self, avId):
if not (avId in self.pendingAvatars):
self.notify.warning(
"%s: tried to clear %s, who was not listed." %
(self.uniqueName, avId))
return
self.notify.debug('%s: clearing avatar %s' % (self.uniqueName, avId))
self.pendingAvatars.remove(avId)
if len(self.pendingAvatars) == 0:
self.notify.debug(
'%s: barrier cleared by %s' % (self.uniqueName, self.avIdList))
self.cleanup()
if self.clearedFunc:
self.clearedFunc()
if self.doneFunc:
self.doneFunc(self.avIdList)
def isActive(self):
return self.active
def getPendingAvatars(self):
return self.pendingAvatars[:]
def __timerExpired(self, task):
self.notify.warning(
'%s: timeout expired; responses not received from %s' %
(self.uniqueName, self.pendingAvatars))
self.cleanup()
# report which avatars have not responded
if self.timeoutFunc:
self.timeoutFunc(self.pendingAvatars[:])
if self.doneFunc:
clearedAvIds = self.avIdList[:]
for avId in self.pendingAvatars:
clearedAvIds.remove(avId)
self.doneFunc(clearedAvIds)
return Task.done
def __handleUnexpectedExit(self, avId):
if avId not in self.avIdList:
return
self.avIdList.remove(avId)
if avId in self.pendingAvatars:
self.clear(avId)

View file

@ -0,0 +1,44 @@
from direct.showbase.DirectObject import DirectObject
from direct.showbase import GarbageReport
class GarbageLeakServerEventAggregator(DirectObject):
def __init__(self, cr):
self.cr = cr
self._doLaterName = None
self._sentLeakDesc2num = {}
self._curLeakDesc2num = {}
self.accept(GarbageReport.GarbageCycleCountAnnounceEvent,
self._handleCycleCounts)
def destroy(self):
self._stopSending()
self.ignoreAll()
del self.cr
def _handleCycleCounts(self, desc2num):
self._curLeakDesc2num = desc2num
self._startSending()
def _startSending(self):
if not self._doLaterName:
self._sendLeaks()
self._doLaterName = uniqueName('%s-sendGarbageLeakInfo' % self.__class__.__name__)
self.doMethodLater(60 * 60., self._sendLeaks, self._doLaterName)
def _stopSending(self):
if self._doLaterName:
self.removeTask(self._doLaterName)
self._doLaterName = None
def _sendLeaks(self, task=None):
for desc, curNum in self._curLeakDesc2num.iteritems():
# only send the number of occurrences of each leak that
# we haven't already sent
self._sentLeakDesc2num.setdefault(desc, 0)
num = curNum - self._sentLeakDesc2num[desc]
if num > 0:
self.cr.timeManager.d_setClientGarbageLeak(num, desc)
self._sentLeakDesc2num[desc] = curNum
if task:
return task.again

View file

@ -0,0 +1,89 @@
from direct.showbase.DirectObject import DirectObject
from direct.showbase import GarbageReport
class GarbageLeakServerEventAggregatorAI(DirectObject):
ClientLeakEvent = 'LeakAggregator-ClientGarbageLeakReceived'
def __init__(self, air):
self.air = air
self._eventFreq = config.GetFloat('garbage-leak-server-event-frequency', 60 * 60.)
self._doLaterName = None
self._sentLeakDesc2num = {}
self._curLeakDesc2num = {}
self.accept(GarbageReport.GarbageCycleCountAnnounceEvent,
self._handleCycleCounts)
self._clientStartFDC = None
self._doLaterNameClient = None
self._sentClientDesc2num = {}
self._curClientDesc2num = {}
self.accept(self.ClientLeakEvent, self._handleClientCycleCount)
def destroy(self):
self.ignoreAll()
self._clientStartFDC.destroy()
self._stopSending()
self._stopSendingClientLeaks()
del self.air
def _handleCycleCounts(self, desc2num):
self._curLeakDesc2num = desc2num
self._startSending()
def _handleClientCycleCount(self, num, description):
self._curClientDesc2num.setdefault(description, 0)
self._curClientDesc2num[description] += num
if not self._clientStartFDC:
# do an FDC to allow other concurrent client events to make it in, for dev/testing
self._clientStartFDC = FrameDelayedCall(
uniqueName('%s-startClientSend' % self.__class__.__name__),
self._startSendingClientLeaks)
def _startSending(self):
if not self._doLaterName:
self._sendLeaks()
self._doLaterName = uniqueName('%s-sendGarbageServerEvents' % self.__class__.__name__)
self.doMethodLater(self._eventFreq, self._sendLeaks, self._doLaterName)
def _stopSending(self):
self.removeTask(self._doLaterName)
self._doLaterName = None
def _sendLeaks(self, task=None):
# only send the number of occurences of each leak that
# we haven't already sent
for desc, curNum in self._curLeakDesc2num.iteritems():
self._sentLeakDesc2num.setdefault(desc, 0)
num = curNum - self._sentLeakDesc2num[desc]
if num > 0:
if hasattr(self.air, 'districtId'):
who = self.air.districtId
eventName = 'ai-garbage'
else:
who = self.air.ourChannel
eventName = 'ud-garbage'
self.air.writeServerEvent(eventName, who, '%s|%s' % (num, desc))
self._sentLeakDesc2num[desc] = curNum
if task:
return task.again
def _startSendingClientLeaks(self):
if not self._doLaterNameClient:
self._sendClientLeaks()
self._doLaterNameClient = uniqueName(
'%s-sendClientGarbageServerEvents' % self.__class__.__name__)
self.doMethodLater(self._eventFreq, self._sendClientLeaks, self._doLaterNameClient)
def _stopSendingClientLeaks(self):
self.removeTask(self._doLaterNameClient)
self._doLaterNameClient = None
def _sendClientLeaks(self, task=None):
# only send the number of occurences of each leak that
# we haven't already sent
for desc, curNum in self._curClientDesc2num.iteritems():
self._sentClientDesc2num.setdefault(desc, 0)
num = curNum - self._sentClientDesc2num[desc]
if num > 0:
self.air.writeServerEvent('client-garbage', self.air.districtId, '%s|%s' % (num, desc))
self._sentClientDesc2num[desc] = curNum
if task:
return task.again

View file

@ -0,0 +1,44 @@
from otp.ai.AIBaseGlobal import *
from pandac.PandaModules import *
from direct.distributed.ClockDelta import *
from direct.task import Task
from direct.showbase import DirectObject
#from direct.directnotify import DirectNotifyGlobal
import time
class GlobalDistributedClassAI(DirectObject.DirectObject):
notify = DirectNotifyGlobal.directNotify.newCategory("GlobalDistributedClassAI")
def __init__(self, air, doid, className):
self.doId = doid
self.air = air
# Setting teh Zone to None means No zone logic for this object
self.zoneId = None
self.dclass = air.dclassesByName[className]
# upside registration
self.air.addDOToTables(self)
self.air.registerForChannel(self.doId)
def remove():
self.air.unregisterForChannel(do.doId)
# This is a race, you may have messages pending delivery that are already
# on there way to or in the local queue:
self.air.removeDOFromTables(self)
del self.air
del sel.doId
#############################
## Support Functions
#############################
def sendUpdateToAvatarIdFromDOID(self, avId, fieldName, args):
channelId = self.GetPuppetConnectionChannel(avId)
self.sendUpdateToChannelFromDOID(channelId, fieldName, args)
########
# Special Function to set return address to the DOID
########
def sendUpdateToChannelFromDOID(self, channelId, fieldName, args):
self.air.sendUpdateToChannelFrom(self, channelId, fieldName,self.doId, args)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,597 @@
from AIBaseGlobal import *
from pandac.PandaModules import *
from direct.distributed import DistributedObjectAI
from direct.directnotify import DirectNotifyGlobal
from otp.otpbase import OTPGlobals
from direct.showbase import PythonUtil, GarbageReport, ContainerReport, MessengerLeakDetector
from direct.showbase import ContainerLeakDetector
from direct.showbase.PythonUtil import Functor, DelayedCall, formatTimeCompact
import fpformat
import string
import time
import re
from direct.task import Task
class MagicWordManagerAI(DistributedObjectAI.DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("MagicWordManagerAI")
supportSuperchat = simbase.config.GetBool('support-superchat', 0)
supportRename = simbase.config.GetBool('support-rename', 0)
# Fill in by subclass
GameAvatarClass = None
# This will hold the local namespace we evaluate '~ai' messages
# within.
ExecNamespace = { }
def __init__(self, air):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
def setMagicWord(self, word, avId, zoneId, signature):
senderId = self.air.getAvatarIdFromSender()
sender = self.air.doId2do.get(senderId, None)
if sender:
if senderId == avId:
sender = "%s/%s(%s)" % (sender.accountName, sender.name, senderId)
else:
sender = "%s/%s(%s) (for %d)" % (sender.accountName, sender.name, senderId, avId)
else:
sender = "Unknown avatar %d" % (senderId)
self.notify.info("%s (%s) just said the magic word: %s" % (sender, signature, word))
self.air.writeServerEvent('magic-word', senderId, "%s|%s|%s" % (sender, signature, word))
if self.air.doId2do.has_key(avId):
av = self.air.doId2do[avId]
try:
self.doMagicWord(word, av, zoneId, senderId)
except:
response = PythonUtil.describeException(backTrace = 1)
self.notify.warning("Ignoring error in magic word:\n%s" % response)
self.down_setMagicWordResponse(senderId, response)
else:
self.notify.info("Don't know avatar %d." % (avId))
def wordIs(self, word, w):
return word == w or word[:(len(w)+1)] == ('%s ' % w)
def getWordIs(self, word):
# bind a word to self.wordIs and return a callable obj
return Functor(self.wordIs, word)
def doMagicWord(self, word, av, zoneId, senderId):
wordIs = self.getWordIs(word)
if wordIs("~rename"):
if (not self.supportRename):
self.notify.warning("Rename is not supported for %s, requested by %d" % (av.name, senderId))
else:
name = string.strip(word[8:])
if name == "":
response = "No name."
else:
av.d_setName(name)
elif wordIs("~badname"):
self.notify.warning("Renaming inappropriately named toon %s (doId %d)." % (av.name, av.doId))
name = "toon%d" % (av.doId % 1000000)
av.d_setName(name)
elif wordIs("~chat"):
if (not self.supportSuperchat) and (senderId != av.doId):
self.notify.warning("Super chat is not supported for %s, requested by %d" % (av.name, senderId))
else:
av.d_setCommonChatFlags(OTPGlobals.CommonChat)
self.notify.debug("Giving common chat permission to " + av.name)
elif wordIs("~superchat"):
if not self.supportSuperchat:
self.notify.warning("Super chat is not supported for " + av.name)
else:
av.d_setCommonChatFlags(OTPGlobals.SuperChat)
self.notify.debug("Giving super chat permission to " + av.name)
elif wordIs("~nochat"):
av.d_setCommonChatFlags(0)
self.notify.debug("Removing special chat permissions for " + av.name)
elif wordIs("~listen"):
if (not self.supportSuperchat) and (senderId != av.doId):
self.notify.warning("Listen is not supported for %s, requested by %d" % (av.name, senderId))
else:
# This is a client-side word.
if (senderId != av.doId):
self.sendUpdateToAvatarId(av.doId, 'setMagicWord', [word, av.doId, zoneId])
elif wordIs("~fix"):
anyChanged = av.fixAvatar()
if anyChanged:
response = "avatar fixed."
else:
response = "avatar does not need fixing."
self.down_setMagicWordResponse(senderId, response)
self.down_setMagicWordResponse(senderId, response)
elif wordIs("~who all"):
str = ''
for obj in self.air.doId2do.values():
if hasattr(obj, "accountName"):
str += '%s %s\n' % (obj.accountName, obj.name)
if not str:
str = "No avatars."
self.down_setMagicWordResponse(senderId, str)
elif wordIs("~ouch"):
if av.hp < 1:
av.b_setHp(0)
av.toonUp(1)
else:
av.b_setHp(1)
self.notify.debug("Only 1 hp for " + av.name)
elif wordIs("~sad"):
av.b_setHp(0)
self.notify.debug("Only 0 hp for " + av.name)
elif wordIs("~dead"):
av.takeDamage(av.hp)
self.notify.debug(av.name + " is dead")
elif wordIs("~waydead"):
av.takeDamage(av.hp)
av.b_setHp(-100)
self.notify.debug(av.name + " is way dead")
elif wordIs("~toonup"):
av.toonUp(av.maxHp)
self.notify.debug("Full heal for " + av.name)
elif wordIs('~hp'):
args = word.split()
hp = int(args[1])
av.b_setHp(hp)
self.notify.debug('Set hp to %s for %s' % (hp, av.name))
elif wordIs("~ainotify"):
args = word.split()
n = Notify.ptr().getCategory(args[1])
n.setSeverity(
{'error': NSError,
'warning': NSWarning,
'info': NSInfo,
'debug': NSDebug,
'spam': NSSpam,}[args[2]])
elif wordIs("~ghost"):
# Toggle ghost mode. Ghost mode == 2 indicates a magic
# word was the source.
if av.ghostMode:
av.b_setGhostMode(0)
else:
av.b_setGhostMode(2)
elif wordIs('~immortal'):
# ~immortal toggles immortal mode on and off
# ~immortal 0/1 and ~immortal on/off sets the mode explicitly
args = word.split()
invalid = False
if len(args) > 1 and args[1] in ('0', 'off'):
immortal = False
elif len(args) > 1 and args[1] in ('1', 'on'):
immortal = True
elif len(args) > 1:
invalid = True
else:
immortal = not av.immortalMode
if invalid:
self.down_setMagicWordResponse(senderId, 'unknown argument %s' % args[1])
else:
# immortality
av.setImmortalMode(immortal)
if av.immortalMode:
response = 'immortality ON'
else:
response = 'immortality OFF'
self.down_setMagicWordResponse(senderId, response)
elif wordIs("~dna"):
# Fiddle with your dna.
self.doDna(word, av, zoneId, senderId)
elif wordIs('~ai'):
# Execute an arbitrary Python command on the AI.
command = string.strip(word[3:])
self.notify.warning("Executing command '%s' from %s" % (command, senderId))
text = self.__execMessage(command)[:simbase.config.GetInt("ai-debug-length",300)]
self.down_setMagicWordResponse(
senderId, text)
elif wordIs('~ud'):
# Execute an arbitrary Python command on the ud.
print word
channel,command = re.match("~ud ([0-9]+) (.+)", word).groups()
channel = int(channel)
if(simbase.air.doId2do.get(channel)):
self.notify.warning("Passing command '%s' to %s from %s" % (command, channel, senderId))
try:
simbase.air.doId2do[channel].sendUpdate("execCommand", [command, self.doId, senderId, zoneId])
except:
pass
elif wordIs('~aiobjects'):
args = word.split()
from direct.showbase import ObjectReport
report = ObjectReport.ObjectReport('AI ~objects')
if 'all' in args:
self.notify.info('printing full object set...')
report.getObjectPool().printObjsByType(printReferrers='ref' in args)
if hasattr(self, 'baselineObjReport'):
self.notify.info('calculating diff from baseline ObjectReport...')
self.lastDiff = self.baselineObjReport.diff(report)
self.lastDiff.printOut(full=('diff' in args or 'dif' in args))
if 'baseline' in args or not hasattr(self, 'baselineObjReport'):
self.notify.info('recording baseline ObjectReport...')
if hasattr(self, 'baselineObjReport'):
self.baselineObjReport.destroy()
self.baselineObjReport = report
self.down_setMagicWordResponse(senderId, 'objects logged')
elif wordIs('~aiobjecthg'):
import gc
objs = gc.get_objects()
type2count = {}
for obj in objs:
tn = safeTypeName(obj)
type2count.setdefault(tn, 0)
type2count[tn] += 1
count2type = invertDictLossless(type2count)
counts = count2type.keys()
counts.sort()
counts.reverse()
for count in counts:
print '%s: %s' % (count, count2type[count])
self.down_setMagicWordResponse(senderId, '~aiobjecthg complete')
elif wordIs('~aicrash'):
# TODO: require a typed explanation in production
# if we call notify.error directly, the magic word mgr will catch it
# self.notify.error doesn't seem to work either
DelayedCall(Functor(simbase.air.notify.error, '~aicrash: simulating an AI crash'))
elif wordIs('~aicontainers'):
args = word.split()
limit = 30
if 'full' in args:
limit = None
ContainerReport.ContainerReport('~aicontainers', log=True, limit=limit, threaded=True)
elif wordIs('~aigarbage'):
args = word.split()
# it can take a LOOONG time to print out the garbage referrers and referents
# by reference (as opposed to by number)
full = ('full' in args)
safeMode = ('safe' in args)
verbose = ('verbose' in args)
delOnly = ('delonly' in args)
def handleGarbageDone(senderId, garbageReport):
self.down_setMagicWordResponse(senderId, 'garbage logged, %s AI cycles' % garbageReport.getNumCycles())
# This does a garbage collection and dumps the list of leaked (uncollectable) objects to the AI log.
GarbageReport.GarbageReport('~aigarbage', fullReport=full, verbose=verbose, log=True, threaded=True,
doneCallback=Functor(handleGarbageDone, senderId), safeMode=safeMode, delOnly=delOnly)
elif wordIs("~creategarbage"):
args = word.split()
num = 1
if len(args) > 1:
num = int(args[1])
GarbageReport._createGarbage(num)
self.down_setMagicWordResponse(senderId, 'leaked garbage created')
elif wordIs('~leaktask'):
def leakTask(task):
return task.cont
taskMgr.add(leakTask, uniqueName('leakedTask'))
leakTask = None
self.down_setMagicWordResponse(senderId, 'leaked task created')
elif wordIs('~aileakmessage'):
MessengerLeakDetector._leakMessengerObject()
self.down_setMagicWordResponse(senderId, 'messenger leak object created')
elif wordIs('~leakContainer'):
ContainerLeakDetector._createContainerLeak()
self.down_setMagicWordResponse(senderId, 'leak container task created')
elif wordIs('~aipstats'):
args = word.split()
hostname = None
port = None
if len(args) > 1:
hostname = args[1]
if len(args) > 2:
port = int(args[2])
# make sure pstats is enabled
simbase.wantStats = 1
Task.TaskManager.pStatsTasks = 1
result = simbase.createStats(hostname, port)
connectionName = '%s' % hostname
if port is not None:
connectionName += ':%s' % port
if result:
response = 'connected AI pstats to %s' % connectionName
else:
response = 'could not connect AI pstats to %s' % connectionName
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aiprofile'):
args = word.split()
if len(args) > 1:
num = int(args[1])
else:
num = 5
session = taskMgr.getProfileSession('~aiprofile')
session.setLogAfterProfile(True)
taskMgr.profileFrames(num, session)
self.down_setMagicWordResponse(senderId, 'profiling %s AI frames...' % num)
elif wordIs('~aiframeprofile'):
args = word.split()
wasOn = bool(taskMgr.getProfileFrames())
if len(args) > 1:
setting = bool(int(args[1]))
else:
setting = not wasOn
taskMgr.setProfileFrames(setting)
self.down_setMagicWordResponse(
senderId,
'AI frame profiling %s%s' % (choice(setting, 'ON', 'OFF'),
choice(wasOn == setting, ' already', '')))
elif wordIs('~aitaskprofile'):
args = word.split()
wasOn = bool(taskMgr.getProfileTasks())
if len(args) > 1:
setting = bool(int(args[1]))
else:
setting = not wasOn
taskMgr.setProfileTasks(setting)
self.down_setMagicWordResponse(
senderId,
'AI task profiling %s%s' % (choice(setting, 'ON', 'OFF'),
choice(wasOn == setting, ' already', '')))
elif wordIs('~aitaskspikethreshold'):
from direct.task.TaskProfiler import TaskProfiler
args = word.split()
if len(args) > 1:
threshold = float(args[1])
response = 'AI task spike threshold set to %ss' % threshold
else:
threshold = TaskProfiler.GetDefaultSpikeThreshold()
response = 'AI task spike threshold reset to %ss' % threshold
TaskProfiler.SetSpikeThreshold(threshold)
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~ailogtaskprofiles'):
args = word.split()
if len(args) > 1:
name = args[1]
else:
name = None
taskMgr.logTaskProfiles(name)
response = 'logged AI task profiles%s' % choice(name, ' for %s' % name, '')
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aitaskprofileflush'):
args = word.split()
if len(args) > 1:
name = args[1]
else:
name = None
taskMgr.flushTaskProfiles(name)
response = 'flushed AI task profiles%s' % choice(name, ' for %s' % name, '')
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aiobjectcount'):
simbase.air.printObjectCount()
self.down_setMagicWordResponse(senderId, 'logging AI distributed object count...')
elif wordIs('~aitaskmgr'):
print taskMgr
self.down_setMagicWordResponse(senderId, 'logging AI taskMgr...')
elif wordIs('~aijobmgr'):
print jobMgr
self.down_setMagicWordResponse(senderId, 'logging AI jobMgr...')
elif wordIs('~aijobtime'):
args = word.split()
if len(args) > 1:
time = float(args[1])
else:
time = None
response = ''
if time is None:
time = jobMgr.getDefaultTimeslice()
time = time * 1000.
response = 'reset AI jobMgr timeslice to %s ms' % time
else:
response = 'set AI jobMgr timeslice to %s ms' % time
time = time / 1000.
jobMgr.setTimeslice(time)
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aidetectleaks'):
started = self.air.startLeakDetector()
self.down_setMagicWordResponse(senderId,
choice(started,
'AI leak detector started',
'AI leak detector already started',
))
elif wordIs('~aitaskthreshold'):
args = word.split()
if len(args) > 1.:
threshold = float(args[1])
else:
threshold = None
response = ''
if threshold is None:
threshold = taskMgr.DefTaskDurationWarningThreshold
response = 'reset AI task duration warning threshold to %s' % threshold
else:
response = 'set AI task duration warning threshold to %s' % threshold
taskMgr.setTaskDurationWarningThreshold(threshold)
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aimessenger'):
print messenger
self.down_setMagicWordResponse(senderId, 'logging AI messenger...')
elif wordIs('~requestdeleted'):
requestDeletedDOs = self.air.getRequestDeletedDOs()
response = '%s requestDeleted AI objects%s' % (
len(requestDeletedDOs), choice(len(requestDeletedDOs), ', logging...', ''))
s = '~requestDeleted: ['
for do, age in requestDeletedDOs:
s += '[%s, %s]' % (do.__class__.__name__, age)
s += ']'
self.notify.info(s)
if len(requestDeletedDOs):
response += '\noldest: %s, %s' % (
requestDeletedDOs[0][0].__class__.__name__,
formatTimeCompact(requestDeletedDOs[0][1]))
self.down_setMagicWordResponse(senderId, response)
elif wordIs('~aigptc'):
args = word.split()
if len(args) > 1. and hasattr(self.cr, 'leakDetector'):
gptcJob = self.cr.leakDetector.getPathsToContainers(
'~aigptc', args[1], Functor(self._handleGPTCfinished, senderId, args[1]))
else:
self.down_setMagicWordResponse(senderId, 'error')
elif wordIs('~aigptcn'):
args = word.split()
if len(args) > 1. and hasattr(self.cr, 'leakDetector'):
gptcnJob = self.cr.leakDetector.getPathsToContainersNamed(
'~aigptcn', args[1], Functor(self._handleGPTCNfinished, senderId, args[1]))
else:
self.down_setMagicWordResponse(senderId, 'error')
else:
# The word is not an AI-side magic word. If the sender is
# different than the target avatar, then pass the magic
# word down to the target client-side MagicWordManager to
# execute a client-side magic word.
# MPG this gets done in child class
#if (senderId != av.doId):
# self.sendUpdateToAvatarId(av.doId, 'setMagicWord', [word, av.doId, zoneId])
return 0
return 1
# MPG define in child class
"""
def doDna(self, word, av, zoneId, senderId):
# Handle the ~dna magic word: change your dna
# Strip of the "~dna" part; everything else is parameters to
# AvatarDNA.updateToonProperties.
parms = string.strip(word[4:])
# Get a copy of the avatar's current DNA.
dna = ToonDNA.ToonDNA(av.dna.makeNetString())
# Modify it according to the user's parameter selection.
eval("dna.updateToonProperties(%s)" % (parms))
av.b_setDNAString(dna.makeNetString())
response = "%s" % (dna.asTuple(),)
self.down_setMagicWordResponse(senderId, response)
"""
def _handleGPTCfinished(self, senderId, ct, gptcJob):
self.down_setMagicWordResponse(senderId, 'aigptc(%s) finished' % ct)
def _handleGPTCNfinished(self, senderId, cn, gptcnJob):
self.down_setMagicWordResponse(senderId, 'aigptcn(%s) finished' % cn)
def __execMessage(self, message):
if not self.ExecNamespace:
# Import some useful variables into the ExecNamespace initially.
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
#self.importExecNamespace()
# Now try to evaluate the expression using ChatInputNormal.ExecNamespace as
# the local namespace.
try:
return str(eval(message, globals(), self.ExecNamespace))
except SyntaxError:
# Maybe it's only a statement, like "x = 1", or
# "import math". These aren't expressions, so eval()
# fails, but they can be exec'ed.
try:
exec message in globals(), self.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
def down_setMagicWordResponse(self, avId, response):
"""down_setMagicWordResponse(self, avId, string response)
Send a response to the avatar who said the magic word.
"""
self.sendUpdateToAvatarId(avId, 'setMagicWordResponse', [response])
def setWho(self, avIds):
# Sent by the client in response to ~who.
str = ''
for avId in avIds:
obj = self.air.doId2do.get(avId, None)
if not obj:
self.air.writeServerEvent('suspicious', avId, 'MagicWordManager.setWho not a valid avId: %s' % avId)
return
elif obj.__class__ == self.GameAvatarClass:
str += '%s %s\n' % (obj.accountName, obj.name)
if not str:
str = "No avatars."
senderId = self.air.getAvatarIdFromSender()
self.down_setMagicWordResponse(senderId, str)
class FakeAv:
# fake avatar object that we can pass in to prevent magic words from crashing
def __init__(self, senderId):
self.hp = 100
self.doId = senderId
self.name = 'FakeAv'
def b_setHp(*args):
pass
def b_setMojo(*args):
pass
def toonUp(*args):
pass
def magicWord(mw, av=None, zoneId=0, senderId=0):
if av is None:
av = FakeAv(senderId)
simbase.air.magicWordManager.doMagicWord(mw, av, zoneId, senderId)
import __builtin__
__builtin__.magicWord = magicWord

18
otp/src/ai/ShowBaseAI.py Normal file
View file

@ -0,0 +1,18 @@
from pandac.PandaModules import WindowProperties
from direct.showbase import ShowBase
class ShowBaseAI(ShowBase.ShowBase):
def __init__(self, windowTitle=None):
self.windowTitle = windowTitle
ShowBase.ShowBase.__init__(self)
def openMainWindow(self, *args, **kw):
ShowBase.ShowBase.openMainWindow(self, *args, **kw)
if self.windowTitle is not None:
wp = WindowProperties()
wp.setTitle(self.windowTitle)
self.win.requestProperties(wp)
def finalizeExit(self):
# don't shut down the app when user closes the window
pass

0
otp/src/ai/Sources.pp Normal file
View file

485
otp/src/ai/TimeManager.py Normal file
View file

@ -0,0 +1,485 @@
# -*- coding: utf-8 -*-
from pandac.PandaModules import *
from direct.showbase.DirectObject import *
from direct.distributed.ClockDelta import *
from direct.task import Task
from direct.distributed import DistributedObject
from direct.directnotify import DirectNotifyGlobal
from otp.otpbase import OTPGlobals
from direct.showbase import PythonUtil
from direct.showbase import GarbageReport
import time
import os
import sys
import re
class TimeManager(DistributedObject.DistributedObject):
"""
This DistributedObject lives on the AI and on the client side, and
serves to synchronize the time between them so they both agree, to
within a few hundred milliseconds at least, what time it is.
This used to use a push model where the AI side would push the
time down to the client periodically, but now it uses a pull model
where the client can request a synchronization check from time to
time. It also employs a round-trip measurement to minimize the
effect of latency.
"""
notify = DirectNotifyGlobal.directNotify.newCategory("TimeManager")
neverDisable = 1
def __init__(self, cr):
DistributedObject.DistributedObject.__init__(self, cr)
# The number of seconds to wait between automatic
# synchronizations. Set to 0 to disable auto sync after
# startup.
self.updateFreq = base.config.GetFloat('time-manager-freq', 1800)
# The minimum number of seconds to wait between two unrelated
# synchronization attempts. Increasing this number cuts down
# on frivolous synchronizations.
self.minWait = base.config.GetFloat('time-manager-min-wait', 10)
# The maximum number of seconds of uncertainty to tolerate in
# the clock delta without trying again.
self.maxUncertainty = base.config.GetFloat('time-manager-max-uncertainty', 1)
# The maximum number of attempts to try to get a low-latency
# time measurement before giving up and accepting whatever we
# get.
self.maxAttempts = base.config.GetInt('time-manager-max-attempts', 5)
# A simulated clock skew for debugging, in seconds.
self.extraSkew = base.config.GetInt('time-manager-extra-skew', 0)
if self.extraSkew != 0:
self.notify.info("Simulating clock skew of %0.3f s" % self.extraSkew)
self.reportFrameRateInterval = base.config.GetDouble('report-frame-rate-interval', 300.0)
self.talkResult = 0
self.thisContext = -1
self.nextContext = 0
self.attemptCount = 0
self.start = 0
self.lastAttempt = -self.minWait*2
self.setFrameRateInterval(self.reportFrameRateInterval)
self._numClientGarbage = 0
### DistributedObject methods ###
def generate(self):
"""
This method is called when the DistributedObject is reintroduced
to the world, either for the first time or from the cache.
"""
self._gotFirstTimeSync = False
if self.cr.timeManager != None:
self.cr.timeManager.delete()
self.cr.timeManager = self
DistributedObject.DistributedObject.generate(self)
self.accept(OTPGlobals.SynchronizeHotkey, self.handleHotkey)
self.accept('clock_error', self.handleClockError)
if __dev__ and base.config.GetBool('enable-garbage-hotkey', 0):
self.accept(OTPGlobals.DetectGarbageHotkey, self.handleDetectGarbageHotkey)
if self.updateFreq > 0:
self.startTask()
def announceGenerate(self):
DistributedObject.DistributedObject.announceGenerate(self)
self.synchronize("TimeManager.announceGenerate")
def gotInitialTimeSync(self):
return self._gotFirstTimeSync
def disable(self):
"""
This method is called when the DistributedObject is removed from
active duty and stored in a cache.
"""
# Warning! disable() is NOT called for TimeManager! Duh!
self.ignore(OTPGlobals.SynchronizeHotkey)
if __dev__:
self.ignore(OTPGlobals.DetectGarbageHotkey)
self.ignore('clock_error')
self.stopTask()
taskMgr.remove('frameRateMonitor')
if self.cr.timeManager == self:
self.cr.timeManager = None
del self._gotFirstTimeSync
DistributedObject.DistributedObject.disable(self)
def delete(self):
"""
This method is called when the DistributedObject is permanently
removed from the world and deleted from the cache.
"""
self.ignore(OTPGlobals.SynchronizeHotkey)
self.ignore(OTPGlobals.DetectGarbageHotkey)
self.ignore('clock_error')
self.stopTask()
taskMgr.remove('frameRateMonitor')
if self.cr.timeManager == self:
self.cr.timeManager = None
DistributedObject.DistributedObject.delete(self)
### Task management methods ###
def startTask(self):
self.stopTask()
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, "timeMgrTask")
def stopTask(self):
taskMgr.remove("timeMgrTask")
def doUpdate(self, task):
self.synchronize("timer")
# Spawn the next one
taskMgr.doMethodLater(self.updateFreq, self.doUpdate, "timeMgrTask")
return Task.done
### User hotkey handling ###
def handleHotkey(self):
# For now, we don't impose any restrictions on the amount of
# time we must wait between user-suggested resyncs. Comment
# this out to change this behavior.
self.lastAttempt = -self.minWait*2
if self.synchronize("user hotkey"):
self.talkResult = 1
else:
# This should change to be more generic
# maybe self.cr.localAv
base.localAvatar.setChatAbsolute("Too soon.", CFSpeech | CFTimeout)
### Automatic clock error handling ###
def handleClockError(self):
self.synchronize("clock error")
### Synchronization methods ###
def synchronize(self, description):
"""synchronize(self, string description)
Call this function from time to time to synchronize watches
with the server. This initiates a round-trip transaction;
when the transaction completes, the time will be synced.
The description is the string that will be written to the log
file regarding the reason for this synchronization attempt.
The return value is true if the attempt is made, or false if
it is too soon since the last attempt.
"""
now = globalClock.getRealTime()
if now - self.lastAttempt < self.minWait:
self.notify.debug("Not resyncing (too soon): %s" % (description))
return 0
self.talkResult = 0
self.thisContext = self.nextContext
self.attemptCount = 0
self.nextContext = (self.nextContext + 1) & 255
self.notify.info("Clock sync: %s" % (description))
self.start = now
self.lastAttempt = now
self.sendUpdate("requestServerTime", [self.thisContext])
return 1
def serverTime(self, context, timestamp, timeOfDay):
"""serverTime(self, int8 context, int32 timestamp, uint32 timeOfDay)
This message is sent from the AI to the client in response to
a previous requestServerTime. It contains the time of day as
observed by the AI.
The client should use this, in conjunction with the time
measurement taken before calling requestServerTime (above), to
determine the clock delta between the AI and the client
machines.
"""
end = globalClock.getRealTime()
# Compare the AI's current time with that previously reported
# by the server at login (and adjusted since then by the local
# clock). It shouldn't be very different.
aiTimeSkew = timeOfDay - self.cr.getServerTimeOfDay()
if context != self.thisContext:
self.notify.info("Ignoring TimeManager response for old context %d" % (context))
return
elapsed = end - self.start
self.attemptCount += 1
self.notify.info("Clock sync roundtrip took %0.3f ms" % (elapsed * 1000.0))
self.notify.info("AI time delta is %s from server delta" % (PythonUtil.formatElapsedSeconds(aiTimeSkew)))
average = (self.start + end) / 2.0 - self.extraSkew
uncertainty = (end - self.start) / 2.0 + abs(self.extraSkew)
globalClockDelta.resynchronize(average, timestamp, uncertainty)
self.notify.info("Local clock uncertainty +/- %.3f s" % (globalClockDelta.getUncertainty()))
if globalClockDelta.getUncertainty() > self.maxUncertainty:
if self.attemptCount < self.maxAttempts:
self.notify.info("Uncertainty is too high, trying again.")
self.start = globalClock.getRealTime()
self.sendUpdate("requestServerTime", [self.thisContext])
return
self.notify.info("Giving up on uncertainty requirement.")
if self.talkResult:
# This should change to be more generic
# maybe self.cr.localAv
base.localAvatar.setChatAbsolute("latency %0.0f ms, sync ±%0.0f ms" % (elapsed * 1000.0, globalClockDelta.getUncertainty() * 1000.0), CFSpeech | CFTimeout)
self._gotFirstTimeSync = True
messenger.send("gotTimeSync")
def setDisconnectReason(self, disconnectCode):
"""setDisconnectReason(self, uint8 disconnectCode)
This method is called by the client just before it leaves a
shard to alert the AI as to the reason it's going. If the AI
doesn't get this message, it can assume the client aborted
messily or its internet connection was dropped.
"""
self.notify.info("Client disconnect reason %s." % (disconnectCode))
self.sendUpdate("setDisconnectReason", [disconnectCode])
def setExceptionInfo(self):
"""
In the case of the client leaving for a Python exception, we
also follow up the above message with this one, which just
sends a text string describing the exception for the AI log.
"""
info = PythonUtil.describeException()
self.notify.info("Client exception: %s" % (info))
self.sendUpdate("setExceptionInfo", [info])
self.cr.flush()
def d_setSignature(self, signature, hash, pyc):
"""
This method is called by the client at startup time, to send
the xrc signature and the prc hash to the AI for logging in
case the client does anything suspicious.
"""
self.sendUpdate("setSignature", [signature, hash, pyc])
def sendCpuInfo(self):
"""
This method is called by the client at startup time, to send
the detailed CPU information to the server for logging.
"""
if not base.pipe:
return
di = base.pipe.getDisplayInformation()
if di.getNumCpuCores() == 0 and hasattr(base.pipe, 'lookupCpuData'):
# If it says we have no CPU's, assume the data hasn't been
# looked up yet, and look it up now.
base.pipe.lookupCpuData()
di = base.pipe.getDisplayInformation()
di.updateCpuFrequency(0)
cacheStatus = preloadCache()
ooghz = 1.0e-009
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz,
di.getCurrentCpuFrequency() * ooghz)
numCpuCores = di.getNumCpuCores()
numLogicalCpus = di.getNumLogicalCpus()
info = '%s|%s|%d|%d|%s|%s cpus' % (
di.getCpuVendorString(), di.getCpuBrandString(),
di.getCpuVersionInformation(), di.getCpuBrandIndex(),
'%0.03f,%0.03f' % cpuSpeed,
'%d,%d' % (numCpuCores, numLogicalCpus))
print "cpu info: %s" % (info)
self.sendUpdate("setCpuInfo", [info, cacheStatus])
def setFrameRateInterval(self, frameRateInterval):
""" This message is called at startup time, to start sending
frame rate reports. """
if frameRateInterval == 0:
return
if not base.frameRateMeter:
# If we're not displaying a frame rate meter, go ahead and
# set the global clock to the same interval, so we will be
# reporting the average frame rate over the whole
# interval. (If we are displaying a frame rate meter,
# don't do this, so the frame rate meter will be more
# responsive.)
# However, we'll put a cap on the frame rate interval, so
# it doesn't go unreasonably wide if we set the reporting
# interval to be fairly slow.
maxFrameRateInterval = base.config.GetDouble('max-frame-rate-interval', 30.0)
globalClock.setAverageFrameRateInterval(min(frameRateInterval, maxFrameRateInterval))
taskMgr.remove('frameRateMonitor')
taskMgr.doMethodLater(frameRateInterval,
self.frameRateMonitor, 'frameRateMonitor')
def frameRateMonitor(self, task):
""" This method is called every once in a while to report the
user's average frame rate to the server. """
from otp.avatar.Avatar import Avatar
vendorId = 0
deviceId = 0
processMemory = 0
pageFileUsage = 0
physicalMemory = 0
pageFaultCount = 0
osInfo = (os.name, 0, 0, 0)
cpuSpeed = (0, 0)
numCpuCores = 0
numLogicalCpus = 0
apiName = 'None'
if getattr(base, 'pipe', None):
di = base.pipe.getDisplayInformation()
if (di.getDisplayState() == DisplayInformation.DSSuccess):
vendorId = di.getVendorId()
deviceId = di.getDeviceId()
di.updateMemoryInformation()
oomb = 1.0 / (1024.0 * 1024.0)
processMemory = di.getProcessMemory() * oomb
pageFileUsage = di.getPageFileUsage() * oomb
physicalMemory = di.getPhysicalMemory() * oomb
pageFaultCount = di.getPageFaultCount() / 1000.0
osInfo = (os.name, di.getOsPlatformId(), di.getOsVersionMajor(), di.getOsVersionMinor())
if sys.platform == 'darwin':
osInfo = self.getMacOsInfo(osInfo)
di.updateCpuFrequency(0)
ooghz = 1.0e-009
cpuSpeed = (di.getMaximumCpuFrequency() * ooghz,
di.getCurrentCpuFrequency() * ooghz)
numCpuCores = di.getNumCpuCores()
numLogicalCpus = di.getNumLogicalCpus()
apiName = base.pipe.getInterfaceName()
self.d_setFrameRate(
max(0, globalClock.getAverageFrameRate()),
max(0, globalClock.calcFrameRateDeviation()),
len(Avatar.ActiveAvatars),
base.locationCode or '',
max(0,time.time() - base.locationCodeChanged),
max(0,globalClock.getRealTime()),
base.gameOptionsCode,
vendorId, deviceId, processMemory, pageFileUsage,
physicalMemory, pageFaultCount, osInfo, cpuSpeed,
numCpuCores, numLogicalCpus, apiName)
return task.again
def d_setFrameRate(self, fps, deviation, numAvs,
locationCode, timeInLocation, timeInGame,
gameOptionsCode, vendorId, deviceId,
processMemory, pageFileUsage, physicalMemory,
pageFaultCount, osInfo, cpuSpeed,
numCpuCores, numLogicalCpus, apiName):
""" Called by frameRateMonitor to report the current frame
rate to the server.
"""
info = '%0.1f fps|%0.3fd|%s avs|%s|%d|%d|%s|0x%04x|0x%04x|%0.1fMB|%0.1fMB|%0.1fMB|%d|%s|%s|%s cpus|%s' % (
fps, deviation, numAvs, locationCode, timeInLocation,
timeInGame, gameOptionsCode,
vendorId, deviceId, processMemory, pageFileUsage, physicalMemory,
pageFaultCount, '%s.%d.%d.%d' % osInfo, '%0.03f,%0.03f' % cpuSpeed,
'%d,%d' % (numCpuCores, numLogicalCpus),
apiName)
print "frame rate: %s" % (info)
self.sendUpdate("setFrameRate", [
fps, deviation, numAvs, locationCode,
timeInLocation, timeInGame, gameOptionsCode,
vendorId, deviceId, processMemory, pageFileUsage,
physicalMemory, pageFaultCount, osInfo, cpuSpeed,
numCpuCores, numLogicalCpus, apiName])
if __dev__:
def handleDetectGarbageHotkey(self):
self._numClientGarbage = GarbageReport.b_checkForGarbageLeaks(wantReply=True)
if self._numClientGarbage:
s = "%s client garbage cycles found, see log" % self._numClientGarbage
else:
s = "0 client garbage cycles found"
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
def d_checkForGarbageLeaks(self, wantReply):
# if wantReply is True, AI will send back a setNumAIGarbageLeaks msg
self.sendUpdate('checkForGarbageLeaks', [wantReply])
def setNumAIGarbageLeaks(self, numLeaks):
if self._numClientGarbage and numLeaks:
s = "%s client and %s AI garbage cycles found, see logs" % (self._numClientGarbage, numLeaks)
elif numLeaks:
s = "0 client and %s AI garbage cycles found, see log" % numLeaks
else:
s = "0 client and 0 AI garbage cycles found"
localAvatar.setChatAbsolute(s, CFSpeech | CFTimeout)
def d_setClientGarbageLeak(self, num, description):
self.sendUpdate('setClientGarbageLeak', [num, description])
def getMacOsInfo(self, defaultOsInfo):
"""Return a tuple of os name, platormid, major ver, minor ver."""
result = defaultOsInfo
try:
theFile = open('/System/Library/CoreServices/SystemVersion.plist')
except IOError:
# hmm plain darwin box do nothing
pass
else:
key = re.search(
r'<key>ProductUserVisibleVersion</key>\s*' +
r'<string>(.*?)</string>', theFile.read())
theFile.close()
if key is not None:
try:
verString = key.group(1)
# we should now have something like 10.5.8
parts = verString.split('.')
major = int(parts[0])
minor = int(parts[1])
bugfix = int(parts[2])
# since platform id is -1, i'll put the bug fix number in there instead, better than an arbitrary number
result = (sys.platform,
bugfix, # what do we put for platform id?
major,
minor)
except Exception, e:
self.notify.debug("getMacOsInfo %s" % str(e))
self.notify.debug('getMacOsInfo returning %s' % str(result))
return result

151
otp/src/ai/TimeManagerAI.py Normal file
View file

@ -0,0 +1,151 @@
from AIBaseGlobal import *
from pandac.PandaModules import *
from direct.distributed.ClockDelta import *
from direct.task import Task
from direct.distributed import DistributedObjectAI
from direct.directnotify import DirectNotifyGlobal
from direct.showbase import GarbageReport
from otp.otpbase import OTPGlobals
from otp.ai.GarbageLeakServerEventAggregatorAI import GarbageLeakServerEventAggregatorAI
import time
class TimeManagerAI(DistributedObjectAI.DistributedObjectAI):
notify = DirectNotifyGlobal.directNotify.newCategory("TimeManagerAI")
def __init__(self, air):
DistributedObjectAI.DistributedObjectAI.__init__(self, air)
if not __dev__:
# double-check that we're not implementing a client-sendable debug DC method in production
if hasattr(self, 'checkForGarbageLeaks'):
self.notify.error('checkForGarbageLeaks should not be defined outside of __dev__')
def requestServerTime(self, context):
"""requestServerTime(self, int8 context)
This message is sent from the client to the AI to initiate a
synchronization phase. The AI should immediately report back
with its current time. The client will then measure the round
trip.
"""
timestamp = globalClockDelta.getRealNetworkTime(bits=32)
requesterId = self.air.getAvatarIdFromSender()
timeOfDay = int(time.time())
self.sendUpdateToAvatarId(requesterId, "serverTime",
[context, timestamp, timeOfDay])
def setDisconnectReason(self, disconnectCode):
"""setDisconnectReason(self, uint8 disconnectCode)
This method is called by the client just before it leaves a
shard to alert the AI as to the reason it's going. If the AI
doesn't get this message, it can assume the client aborted
messily or its internet connection was dropped.
"""
requesterId = self.air.getAvatarIdFromSender()
self.notify.info("Client %s leaving for reason %s (%s)." % (
requesterId, disconnectCode,
OTPGlobals.DisconnectReasons.get(disconnectCode,
'invalid reason')))
if disconnectCode in OTPGlobals.DisconnectReasons:
self.air.setAvatarDisconnectReason(requesterId, disconnectCode)
else:
self.air.writeServerEvent(
'suspicious', requesterId, 'invalid disconnect reason: %s' % disconnectCode)
def setExceptionInfo(self, info):
"""setExceptionInfo(self, string info)
In the case of the client leaving for a Python exception, we
also follow up the above message with this one, which just
sends a text string describing the exception for the AI log.
"""
requesterId = self.air.getAvatarIdFromSender()
self.notify.info("Client %s exception: %s" % (requesterId, info))
serverVersion = simbase.config.GetString('server-version','')
self.air.writeServerEvent('client-exception', requesterId, '%s|%s' % (serverVersion,info))
def setSignature(self, signature, hash, pyc):
"""
This method is called by the client at startup time, to send
the xrc signature and the prc hash to the AI for logging in
case the client does anything suspicious.
"""
if signature:
requesterId = self.air.getAvatarIdFromSender()
prcHash = HashVal()
prcHash.setFromBin(hash)
info = '%s|%s' % (signature, prcHash.asHex())
self.notify.info('Client %s signature: %s' % (requesterId, info))
self.air.writeServerEvent('client-signature', requesterId, info)
pycHash = HashVal()
pycHash.setFromBin(pyc)
if pycHash != HashVal():
info = pycHash.asHex()
self.notify.info('Client %s py signature: %s' % (requesterId, info))
self.air.writeServerEvent('client-py-signature', requesterId, info)
def setCpuInfo(self, info, cacheStatus):
"""
This method is called by the client at startup time, to send
the detailed CPU information to the server for logging.
"""
requesterId = self.air.getAvatarIdFromSender()
self.notify.info('client-cpu %s|%s' % (requesterId, info))
self.air.writeServerEvent('client-cpu', requesterId, info)
# We call this cacheStatus, but really it's the mac address or
# other client fingerprint information, in a simple
# obfuscating cipher. Decode it.
key = 'outrageous'
p = 0
fingerprint = ''
for ch in cacheStatus:
ic = ord(ch) ^ ord(key[p])
p += 1
if p >= len(key):
p = 0
fingerprint += chr(ic)
self.notify.info('client-fingerprint %s|%s' % (requesterId, fingerprint))
self.air.writeServerEvent('client-fingerprint', requesterId, fingerprint)
if hasattr(self.air, 'cpuInfoMgr'):
self.air.cpuInfoMgr.sendCpuInfoToUd(info, fingerprint)
def setFrameRate(self, fps, deviation, numAvs,
locationCode, timeInLocation, timeInGame,
gameOptionsCode, vendorId, deviceId,
processMemory, pageFileUsage, physicalMemory,
pageFaultCount, osInfo, cpuSpeed,
numCpuCores, numLogicalCpus, apiName):
""" This method is called by the client at the interval
specified by getFrameRateInterval(), to report its current
frame rate. """
requesterId = self.air.getAvatarIdFromSender()
info = '%0.1f fps|%0.3fd|%s avs|%s|%d|%d|%s|0x%04x|0x%04x|%0.1fMB|%0.1fMB|%0.1fMB|%d|%s|%s|%s cpus|%s' % (
fps, deviation, numAvs, locationCode, timeInLocation,
timeInGame, gameOptionsCode,
vendorId, deviceId, processMemory, pageFileUsage, physicalMemory,
pageFaultCount, '%s.%d.%d.%d' % osInfo, '%0.03f,%0.03f' % cpuSpeed,
'%d,%d' % (numCpuCores, numLogicalCpus),
apiName)
self.notify.info('client-fps %s|%s' % (requesterId, info))
self.air.writeServerEvent('client-fps', requesterId, info)
if __dev__:
def checkForGarbageLeaks(self, wantReply):
senderId = self.air.getAvatarIdFromSender()
self.notify.info("checking for garbage leaks requested by %s" % senderId)
# okay checking for garbage leaks should only be done by devs, it's rare enough i'll flag it
# as suspicious
self.air.writeServerEvent('suspicious', senderId, 'checkForGarbageLeaks')
numLeaks = GarbageReport.checkForGarbageLeaks()
if wantReply:
requesterId = self.air.getAvatarIdFromSender()
self.sendUpdateToAvatarId(requesterId, 'setNumAIGarbageLeaks', [numLeaks])
def setClientGarbageLeak(self, num, description):
messenger.send(GarbageLeakServerEventAggregatorAI.ClientLeakEvent, [num, description])

0
otp/src/ai/__init__.py Normal file
View file

View file

@ -0,0 +1,4 @@
.cvsignore
Makefile
*.pyc
pp.dep

1010
otp/src/avatar/Avatar.py Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
"""
AvatarDNA module: contains the methods and definitions for describing
multipart actors with a simple class
"""
#import whrandom
from pandac.PandaModules import *
from direct.directnotify.DirectNotifyGlobal import *
import random
from direct.distributed.PyDatagram import PyDatagram
from direct.distributed.PyDatagramIterator import PyDatagramIterator
notify = directNotify.newCategory("AvatarDNA")
class AvatarDNA:
"""
Contains methods for describing avatars with a
simple class. The AvatarDNA class may be converted to lists of strings
for network transmission. Also, AvatarDNA objects can be constructed
from lists of strings recieved over the network. Some examples are in
order.
# create a toon from a network packet (list of strings)
dna = AvatarDNA()
dna.makeFromNetString(networkPacket)
"""
# special methods
def __str__(self):
"""
Avatar DNA print method
"""
return "avatar parent class: type undefined"
# stringification methods
def makeNetString(self):
notify.error("called makeNetString on avatarDNA parent class")
def printNetString(self):
string = self.makeNetString()
dg = PyDatagram(string)
dg.dumpHex(ostream)
def makeFromNetString(self, string):
notify.error("called makeFromNetString on avatarDNA parent class")
# dna methods
def getType(self):
"""
Return which type of actor this dna represents.
"""
notify.error("Invalid DNA type: ", self.type)
return type

View file

@ -0,0 +1,80 @@
from direct.directnotify.DirectNotifyGlobal import directNotify
from otp.avatar import Avatar
"""
instantiate this class with an avatar Id and a callback,
and the callback will be called when the avatar is loaded.
NOTE: if there is a problem, the avatar will be "None"!
"""
class AvatarDetail:
notify = directNotify.newCategory("AvatarDetail")
#notify.setDebug(True)
def __init__(self, doId, callWhenDone):
#print("Getting avatar detail for %s from the DB" % doId)
self.id = doId
self.callWhenDone = callWhenDone
self.enterQuery()
def isReady(self):
return true
def getId(self):
return self.id
##### Query state #####
# We are waiting for detailed information on the avatar to return
# from the server.
def enterQuery(self):
# We need to get a DistributedObject handle for the indicated
# avatar. Maybe we have one already, if the avatar is
# somewhere nearby.
self.avatar = base.cr.doId2do.get(self.id)
if self.avatar != None and not self.avatar.ghostMode:
self.createdAvatar = 0
dclass=self.getDClass()
self.__handleResponse(True, self.avatar, dclass)
else:
# Otherwise, we have to make one up just to hold the
# detail query response. This is less than stellar,
# because it means we'll do a lot of extra work we don't
# need (like loading up models and binding animations,
# etc.), but it's not *too* horrible.
self.avatar = self.createHolder()
self.createdAvatar = 1
self.avatar.doId = self.id
# Now ask the server to tell us more about this avatar.
dclass = self.getDClass()
base.cr.getAvatarDetails(self.avatar, self.__handleResponse, dclass)
def exitQuery(self):
return true
def createHolder(self):
assert 0, "This must be defined by the subclass!"
def getDClass(self):
assert 0, "This must be defined by the subclass!"
def __handleResponse(self, gotData, avatar, dclass):
if (avatar != self.avatar):
# This may be a query response coming back from a previous
# request. Ignore it.
self.notify.warning("Ignoring unexpected request for avatar %s" % (avatar.doId))
return
if gotData:
# We got a valid response.
self.callWhenDone(self.avatar)
del self.callWhenDone
else:
# No information available about the avatar. This is an
# unexpected error condition, but we go out of our way to
# handle it gracefully.
self.callWhenDone(None)
del self.callWhenDone

View file

@ -0,0 +1,20 @@
class AvatarHandle:
dclassName = "AvatarHandle"
def getName(self):
if __dev__:
assert False, 'Must override this in inheriting class'
return ''
def isOnline(self):
if __dev__:
assert False, 'Must override this in inheriting class'
return False
def isUnderstandable(self):
if __dev__:
assert False, 'Must override this in inheriting class'
return True
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = localAvatar.scrubTalk(chat, mods)
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.avatarId, self.getName(), newText, scrubbed)

View file

@ -0,0 +1,98 @@
from pandac.PandaModules import *
from direct.gui.DirectGui import *
from direct.showbase import DirectObject
import Avatar
from direct.distributed import DistributedObject
class AvatarPanel(DirectObject.DirectObject):
"""
This is a panel that pops up in response to clicking on a Toon or
Cog nearby you, or to picking a Toon from your friends list. It
draws a little picture of the avatar's head, and gives you a few
options to pick from re the avatar.
"""
# Limit to only have one avatar panel at a time
currentAvatarPanel = None
def __init__(self, avatar, FriendsListPanel = None):
# You can only have one open at a time
if AvatarPanel.currentAvatarPanel:
AvatarPanel.currentAvatarPanel.cleanup()
AvatarPanel.currentAvatarPanel = self
# Clean up any friends list panels that may be up
self.friendsListShown = False
self.FriendsListPanel = FriendsListPanel
if FriendsListPanel:
self.friendsListShown = FriendsListPanel.isFriendsListShown()
FriendsListPanel.hideFriendsList()
if avatar:
self.avatar = avatar
self.avName = avatar.getName()
else:
self.avatar = None
self.avName = "Player"
if (hasattr(avatar, "uniqueName")):
self.avId = avatar.doId
self.avDisableName = avatar.uniqueName('disable')
self.avGenerateName = avatar.uniqueName('generate')
self.avHpChangeName = avatar.uniqueName('hpChange')
# If we have an actual DistributedObject for this avatar, use
# that one instead of whatever we're given.
if base.cr.doId2do.has_key(self.avId):
self.avatar = base.cr.doId2do[self.avId]
else:
self.avDisableName = None
self.avGenerateName = None
self.avHpChangeName = None
self.avId = None
if self.avDisableName:
self.accept(self.avDisableName, self.__handleDisableAvatar)
def cleanup(self):
if AvatarPanel.currentAvatarPanel != self:
# Must already be cleaned up
return
if self.avDisableName:
self.ignore(self.avDisableName)
if self.avGenerateName:
self.ignore(self.avGenerateName)
if self.avHpChangeName:
self.ignore(self.avHpChangeName)
AvatarPanel.currentAvatarPanel = None
def __handleClose(self):
self.cleanup()
AvatarPanel.currentAvatarPanel = None
if self.friendsListShown:
# Restore the friends list if it was up before.
self.FriendsListPanel.showFriendsList()
def __handleDisableAvatar(self):
# the old __handleDisableAvatar was sneaking past the inherited class
if AvatarPanel.currentAvatarPanel:
AvatarPanel.currentAvatarPanel.handleDisableAvatar()
else:
self.handleDisableAvatar()
def handleDisableAvatar(self):
"""
Called whenever an avatar is disabled, this should cleanup the
avatar panel if it's not a friend.
"""
# If the avatar wandered away (or disconnected) shut down the panel.
self.cleanup()
AvatarPanel.currentAvatarPanel = None
def isHidden(self):
# this function should be sub-classed
return 1
def getType(self):
return None

View file

@ -0,0 +1,446 @@
import time
import string
from pandac.PandaModules import *
from direct.distributed import DistributedNode
from direct.actor.DistributedActor import DistributedActor
from direct.task import Task
from direct.showbase import PythonUtil
from libotp import Nametag
from otp.otpbase import OTPGlobals
from otp.otpbase import OTPLocalizer
from otp.speedchat import SCDecoders
from otp.chat import ChatGarbler
from otp.chat import ChatManager
import random
from Avatar import Avatar
import AvatarDNA
class DistributedAvatar(DistributedActor, Avatar):
# This is a text node used to create the numbers that appear over the
# heads of the avatars.
HpTextGenerator = TextNode("HpTextGenerator")
# This is used to enable/disable the display of the hp numbers
HpTextEnabled = 1
# set this True so that we can start accepting nametagAmbientLightChanged in generate
# and ignore it in disable
ManagesNametagAmbientLightChanged = True
def __init__(self, cr):
"""
Handle distributed updates
"""
try:
self.DistributedAvatar_initialized
return
except:
self.DistributedAvatar_initialized = 1
Avatar.__init__(self)
DistributedActor.__init__(self, cr)
# The node that shows the number of hp just gained or lost
self.hpText = None
self.hp = None
self.maxHp = None
### managing ActiveAvatars ###
def disable(self):
"""
This method is called when the DistributedObject is removed from
active duty and stored in a cache.
"""
try:
del self.DistributedAvatar_announced
except:
return
self.reparentTo(hidden)
self.removeActive()
self.disableBodyCollisions()
self.hideHpText()
# By setting hp to None, when the distributed avatar is "uncached",
# and the hp gets set, it will be as if the avatar is new, and no
# number will appear over his head. If we don't set this to None,
# the setHp call might think that the number has changed and call
# showHpText, which we don't want.
self.hp = None
self.ignore("nameTagShowAvId")
self.ignore("nameTagShowName")
DistributedActor.disable(self)
def delete(self):
"""
This method is called when the DistributedObject is permanently
removed from the world and deleted from the cache.
"""
try:
self.DistributedAvatar_deleted
except:
self.DistributedAvatar_deleted = 1
Avatar.delete(self)
DistributedActor.delete(self)
def generate(self):
"""
This method is called when the DistributedObject is reintroduced
to the world, either for the first time or from the cache.
"""
DistributedActor.generate(self)
if not self.isLocal():
self.addActive()
self.considerUnderstandable()
# Initially, a DistributedAvatar is always parented to hidden
# on generate, until we are told otherwise.
self.setParent(OTPGlobals.SPHidden)
# Now that we have a doId, set a tag so others who find us in
# the collision system can figure out what avatar they hit.
self.setTag('avatarDoId', str(self.doId))
self.accept("nameTagShowAvId",self.__nameTagShowAvId)
self.accept("nameTagShowName",self.__nameTagShowName)
def announceGenerate(self):
try:
self.DistributedAvatar_announced
return
except:
self.DistributedAvatar_announced = 1
if(not self.isLocal()):
self.initializeBodyCollisions("distAvatarCollNode-" + str(self.doId))
DistributedActor.announceGenerate(self)
def __setTags(self, extra = None):
if hasattr(base, "idTags"):
if base.idTags:
self.__nameTagShowAvId()
else:
self.__nameTagShowName()
### setParent ###
def do_setParent(self, parentToken):
"""do_setParent(self, int parentToken)
This overrides a function defined in DistributedNode to
reparent the node somewhere. A DistributedAvatar wants to
hide the onscreen nametag when the parent is hidden.
"""
if not self.isDisabled():
if parentToken == OTPGlobals.SPHidden:
self.nametag2dDist &= ~Nametag.CName
else:
self.nametag2dDist |= Nametag.CName
self.nametag.getNametag2d().setContents(
self.nametag2dContents & self.nametag2dDist)
DistributedActor.do_setParent(self, parentToken)
self.__setTags()
### setHp ###
def toonUp(self, hpGained):
# WARNING This is extended in DistributedToon.py, please change that
# as well if any changes are made here
# Adjusts the avatar's hp upward by the indicated value
# (limited by maxHp) and shows green numbers flying out of the
# avatar's head.
if self.hp == None or hpGained < 0:
return
oldHp = self.hp
# If hp is below zero, it might mean we're at a timeout in the
# playground, in which case we respect that it is below zero
# until we get our head above water. If our toonUp would
# take us above zero, then we pretend we started at zero in
# the first place, ignoring the timeout.
if self.hp + hpGained <= 0:
self.hp += hpGained
else:
self.hp = min(max(self.hp, 0) + hpGained, self.maxHp)
hpGained = self.hp - max(oldHp, 0)
if hpGained > 0:
self.showHpText(hpGained)
self.hpChange(quietly = 0)
def takeDamage(self, hpLost, bonus=0):
# Adjusts the avatar's hp downward by the indicated value
# (limited by 0) and shows red numbers flying out of the
# avatar's head.
if self.hp == None or hpLost < 0:
return
oldHp = self.hp
self.hp = max(self.hp - hpLost, 0)
hpLost = oldHp - self.hp
if hpLost > 0:
self.showHpText(-hpLost, bonus)
self.hpChange(quietly = 0)
if self.hp <= 0 and oldHp > 0:
self.died()
def setHp(self, hitPoints):
# We no longer fly numbers out of the avatar's head just for
# calling setHp(). Instead, toonUp() and takeDamage() divide
# that responsibility, and setHp() is just used to quietly
# reset the hp from the AI.
justRanOutOfHp = (hitPoints is not None and
self.hp is not None and
self.hp - hitPoints > 0 and
hitPoints <= 0)
# Store the new value.
self.hp = hitPoints
# Send events so that the hp meter and others can know about the
# change to hp.
self.hpChange(quietly = 1)
if justRanOutOfHp:
self.died()
def hpChange(self, quietly = 0):
# We may not have a doId yet... in which case we can't send the
# event, and don't need to anyway.
if hasattr(self, "doId"):
if self.hp != None and self.maxHp != None:
messenger.send(self.uniqueName("hpChange"), [self.hp, self.maxHp, quietly])
if self.hp != None and self.hp > 0:
messenger.send(self.uniqueName("positiveHP"))
def died(self):
"""
This is a hook for derived classes to do something when the
avatar runs out of HP. The base function doesn't do anything.
"""
pass
def getHp(self):
return self.hp
### setMaxHp ###
def setMaxHp(self, hitPoints):
self.maxHp = hitPoints
self.hpChange()
def getMaxHp(self):
return self.maxHp
### getName ###
def getName(self):
return(Avatar.getName(self))
def setName(self, name):
# Set the name of our top node, so it will be easy to identify
# this avatar in the scene graph.
try:
self.node().setName("%s-%d" % (name, self.doId))
self.gotName = 1
except:
# This might fail if the doId hasn't been set yet.
# No big deal.
pass
return(Avatar.setName(self, name))
### hpText ####
def showHpText(self, number, bonus=0, scale=1):
# WARNING if this changes please also change DistributedToon.py
if self.HpTextEnabled and not self.ghostMode:
# We don't show zero change.
if number != 0:
# Get rid of the number if it is already there.
if self.hpText:
self.hideHpText()
# Set the font
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
# Show both negative and positive signs
if number < 0:
self.HpTextGenerator.setText(str(number))
else:
self.HpTextGenerator.setText("+" + str(number))
# No shadow
self.HpTextGenerator.clearShadow()
# Put a shadow on there
#self.HpTextGenerator.setShadow(0.05, 0.05)
#self.HpTextGenerator.setShadowColor(0, 0, 0, 1)
# Center the number
self.HpTextGenerator.setAlign(TextNode.ACenter)
# Red for negative, green for positive, yellow for bonus
if bonus == 1:
r = 1.0
g = 1.0
b = 0
a = 1
elif bonus == 2:
r = 1.0
g = 0.5
b = 0
a = 1
elif number < 0:
r = 0.9
g = 0
b = 0
a = 1
else:
r = 0
g = 0.9
b = 0
a = 1
self.HpTextGenerator.setTextColor(r, g, b, a)
self.hpTextNode = self.HpTextGenerator.generate()
# Put the hpText over the head of the avatar
self.hpText = self.attachNewNode(self.hpTextNode)
self.hpText.setScale(scale)
# Make sure it is a billboard
self.hpText.setBillboardPointEye()
# Render it after other things in the scene.
self.hpText.setBin('fixed', 100)
# Initial position ... Center of the body... the "tan tien"
self.hpText.setPos(0, 0, self.height/2)
seq = Task.sequence(
# Fly the number out of the character
self.hpText.lerpPos(Point3(0, 0, self.height + 1.5),
1.0,
blendType = 'easeOut'),
# Wait 2 seconds
Task.pause(0.85),
# Fade the number
self.hpText.lerpColor(Vec4(r, g, b, a),
Vec4(r, g, b, 0),
0.1),
# Get rid of the number
Task.Task(self.hideHpTextTask))
taskMgr.add(seq, self.uniqueName("hpText"))
else:
# Just play the sound effect.
# TODO: Put in the sound effect!
pass
def showHpString(self, text, duration=0.85, scale=0.7):
if self.HpTextEnabled and not self.ghostMode:
# We don't show empty strings
if text != '':
# Get rid of text if it is already there.
if self.hpText:
self.hideHpText()
# Set the font
self.HpTextGenerator.setFont(OTPGlobals.getSignFont())
# Write the text
self.HpTextGenerator.setText(text)
# No shadow
self.HpTextGenerator.clearShadow()
# Put a shadow on there
#self.HpTextGenerator.setShadow(0.05, 0.05)
#self.HpTextGenerator.setShadowColor(0, 0, 0, 1)
# Center the text
self.HpTextGenerator.setAlign(TextNode.ACenter)
# Set the color and alpha scale (a)
r = a = 1.0
g = b = 0.0
self.HpTextGenerator.setTextColor(r, g, b, a)
self.hpTextNode = self.HpTextGenerator.generate()
# Put the hpText over the head of the avatar
self.hpText = self.attachNewNode(self.hpTextNode)
# Set its scale
self.hpText.setScale(scale)
# Make sure it is a billboard
self.hpText.setBillboardAxis()
# Initial position ... Center of the body... the "tan tien"
self.hpText.setPos(0, 0, self.height/2)
seq = Task.sequence(
# Fly the number out of the character
self.hpText.lerpPos(Point3(0, 0, self.height + 1.5),
1.0,
blendType = 'easeOut'),
# Wait 2 seconds
Task.pause(duration),
# Fade the number
self.hpText.lerpColor(Vec4(r, g, b, a),
Vec4(r, g, b, 0),
0.1),
# Get rid of the number
Task.Task(self.hideHpTextTask))
taskMgr.add(seq, self.uniqueName("hpText"))
else:
# Just play the sound effect.
# TODO: Put in the sound effect!
pass
def hideHpTextTask(self, task):
self.hideHpText()
return Task.done
def hideHpText(self):
if self.hpText:
taskMgr.remove(self.uniqueName("hpText"))
self.hpText.removeNode()
self.hpText = None
def getStareAtNodeAndOffset(self):
return self, Point3(0,0,self.height)
def getAvIdName(self):
# Derived classes can override the base.idTags display.
return "%s\n%s" % (self.getName(), self.doId)
def __nameTagShowAvId(self, extra = None):
self.setDisplayName(self.getAvIdName())
def __nameTagShowName(self, extra = None):
self.setDisplayName(self.getName())
def askAvOnShard(self, avId):
#determines if a given avId in on my shard
if base.cr.doId2do.get(avId):
#print("Found Locally")
messenger.send("AvOnShard%s"%(avId), [True])
else:
#print("asking AI")
self.sendUpdate("checkAvOnShard", [avId])
def confirmAvOnShard(self, avId, onShard = True):
messenger.send(("AvOnShard%s"%(avId)), [onShard])
### play dialog sounds ###
def getDialogueArray(self):
# Inheritors should override
return None

View file

@ -0,0 +1,103 @@
from otp.ai.AIBaseGlobal import *
from otp.otpbase import OTPGlobals
from direct.fsm import ClassicFSM
from direct.fsm import State
from direct.distributed import DistributedNodeAI
from direct.task import Task
class DistributedAvatarAI(DistributedNodeAI.DistributedNodeAI):
def __init__(self, air):
DistributedNodeAI.DistributedNodeAI.__init__(self, air)
self.hp = 0
self.maxHp = 0
def b_setName(self, name):
self.setName(name)
self.d_setName(name)
def d_setName(self, name):
self.sendUpdate("setName", [name])
def setName(self, name):
self.name = name
def getName(self):
return self.name
def b_setMaxHp(self, maxHp):
self.d_setMaxHp(maxHp)
self.setMaxHp(maxHp)
def d_setMaxHp(self, maxHp):
self.sendUpdate('setMaxHp', [maxHp])
def setMaxHp(self, maxHp):
self.maxHp = maxHp
def getMaxHp(self):
return self.maxHp
def b_setHp(self, hp):
self.d_setHp(hp)
self.setHp(hp)
def d_setHp(self, hp):
self.sendUpdate('setHp', [hp])
def setHp(self, hp):
self.hp = hp
def getHp(self):
return self.hp
#----------------------------------
def b_setLocationName(self, locationName):
self.d_setLocationName(locationName)
self.setLocationName(locationName)
def d_setLocationName(self, locationName):
pass
def setLocationName(self, locationName):
self.locationName = locationName
def getLocationName(self):
return self.locationName
#----------------------------------
def b_setActivity(self, activity):
self.d_setActivity(activity)
self.setActivity(activity)
def d_setActivity(self, activity):
pass
def setActivity(self, activity):
self.activity = activity
def getActivity(self):
return self.activity
#----------------------------------
def toonUp(self, num):
# The default toonup is HP recharge. If other games want
# a more involved toonup, they can redefine this function
if self.hp >= self.maxHp:
return
self.hp = min(self.hp + num, self.maxHp)
self.b_setHp(self.hp)
def getRadius(self):
return OTPGlobals.AvatarDefaultRadius
def checkAvOnShard(self, avId):
senderId = self.air.getAvatarIdFromSender()
onShard = False
if simbase.air.doId2do.get(avId):
onShard = True
self.sendUpdateToAvatarId(senderId,"confirmAvOnShard",[avId, onShard])

View file

@ -0,0 +1,27 @@
from otp.ai.AIBaseGlobal import *
from otp.otpbase import OTPGlobals
#from direct.fsm import ClassicFSM
#from direct.fsm import State
from direct.distributed.DistributedNodeAI import DistributedNodeAI
#from direct.task import Task
class DistributedAvatarUD(DistributedNodeAI):
def __init__(self, air):
DistributedNodeAI.__init__(self, air)
self.hp = 0
self.maxHp = 0
def b_setName(self, name):
self.setName(name)
self.d_setName(name)
def d_setName(self, name):
self.sendUpdate("setName", [name])
def setName(self, name):
self.name = name
def getName(self):
return self.name

View file

@ -0,0 +1,707 @@
"""DistributedPlayer module: contains the DistributedPlayer class"""
from pandac.PandaModules import *
from libotp import WhisperPopup
from libotp import CFQuicktalker, CFPageButton, CFQuitButton, CFSpeech, CFThought, CFTimeout
from otp.chat import ChatGarbler
import string
from direct.task import Task
from otp.otpbase import OTPLocalizer
from otp.speedchat import SCDecoders
from direct.showbase import PythonUtil
from otp.avatar import DistributedAvatar
import time
from otp.avatar import Avatar, PlayerBase
from otp.chat import TalkAssistant
from otp.otpbase import OTPGlobals
#hack, init for client-side outgoing chat filter
if base.config.GetBool('want-chatfilter-hacks',0):
from otp.switchboard import badwordpy
import os
badwordpy.init(os.environ.get('OTP')+'\\src\\switchboard\\','')
class DistributedPlayer(DistributedAvatar.DistributedAvatar,
PlayerBase.PlayerBase):
"""Distributed Player class:"""
# This is the length of time that should elapse before we allow
# another failed-teleport message to be displayed from the same
# avatar.
TeleportFailureTimeout = 60.0
# Create a default chat garbler (can be overridden by child class)
chatGarbler = ChatGarbler.ChatGarbler()
def __init__(self, cr):
"""
Handle distributed updates
"""
try:
self.DistributedPlayer_initialized
except:
self.DistributedPlayer_initialized = 1
DistributedAvatar.DistributedAvatar.__init__(self, cr)
PlayerBase.PlayerBase.__init__(self)
self.__teleportAvailable = 0
self.inventory = None
self.experience = None
self.friendsList = []
self.oldFriendsList = None
self.timeFriendsListChanged = None
self.ignoreList = []
self.lastFailedTeleportMessage = {}
self._districtWeAreGeneratedOn = None
self.DISLname = ""
self.DISLid = 0
self.autoRun = 0
self.whiteListEnabled = base.config.GetBool('whitelist-chat-enabled', 1)
### managing ActiveAvatars ###
def disable(self):
"""
This method is called when the DistributedObject is removed from
active duty and stored in a cache.
"""
DistributedAvatar.DistributedAvatar.disable(self)
def delete(self):
"""
This method is called when the DistributedObject is permanently
removed from the world and deleted from the cache.
"""
try:
self.DistributedPlayer_deleted
except:
self.DistributedPlayer_deleted = 1
del self.experience
if self.inventory:
self.inventory.unload()
del self.inventory
DistributedAvatar.DistributedAvatar.delete(self)
def generate(self):
"""
This method is called when the DistributedObject is reintroduced
to the world, either for the first time or from the cache.
"""
DistributedAvatar.DistributedAvatar.generate(self)
def setLocation(self, parentId, zoneId, teleport=0):
DistributedAvatar.DistributedAvatar.setLocation(self, parentId, zoneId, teleport)
# if the avatar just got put somewhere it shouldn't be, delete it
# this is to prevent hackers from sidling over into an 'uber' zone, thereby
# keeping themselves on your client even after the client no longer has interest in the
# original, legitimate zone from which the hacker toon was generated
if not (parentId in (0, None) and zoneId in (0, None)):
if not self.cr._isValidPlayerLocation(parentId, zoneId):
self.cr.disableDoId(self.doId)
self.cr.deleteObject(self.doId)
def isGeneratedOnDistrict(self, districtId=None):
if districtId is None:
return self._districtWeAreGeneratedOn is not None
else:
return self._districtWeAreGeneratedOn == districtId
def getArrivedOnDistrictEvent(self, districtId=None):
if districtId is None:
return 'arrivedOnDistrict'
else:
return 'arrivedOnDistrict-%s' % districtId
def arrivedOnDistrict(self, districtId):
# we have been generated on this district
curFrameTime = globalClock.getFrameTime()
if hasattr(self,"frameTimeWeArrivedOnDistrict") and \
curFrameTime == self.frameTimeWeArrivedOnDistrict:
# rare case check if we get the zero from the shard we're leaving
# AFTER we get the district id of the shard we were going to
if districtId == 0 and self._districtWeAreGeneratedOn:
self.notify.warning("ignoring arrivedOnDistrict 0, since arrivedOnDistrict %d occured on the same frame" % self._districtWeAreGeneratedOn)
return
self._districtWeAreGeneratedOn = districtId
self.frameTimeWeArrivedOnDistrict = globalClock.getFrameTime()
messenger.send(self.getArrivedOnDistrictEvent(districtId))
messenger.send(self.getArrivedOnDistrictEvent())
def setLeftDistrict(self):
self._districtWeAreGeneratedOn = None
def hasParentingRules(self):
# we can't define setParentingRules for the localAvatar in the DC because
# that would define parenting rules for other players' avatars. Just
# override this and always return True for the sake of the DoInterestManager
if self is localAvatar:
return True
### setAccountName ###
def setAccountName(self, accountName):
self.accountName = accountName
### setWhisper ###
def setSystemMessage(self, aboutId, chatString,
whisperType = WhisperPopup.WTSystem):
"""setSystemMessage(self, int aboutId, string chatString)
A message generated from the system (or the AI, or something
like that). If this involves another avatar (e.g. Flippy is
now online), the aboutId is filled in; otherwise, aboutId is
zero.
"""
self.displayWhisper(aboutId, chatString, whisperType)
def displayWhisper(self, fromId, chatString, whisperType):
"""displayWhisper(self, int fromId, string chatString, int whisperType)
Displays the whisper message in whatever capacity makes sense.
This is separate from setWhisper so we can safely call it by
name from within setWhisper and expect the derived function to
override it.
"""
print "Whisper type %s from %s: %s" % (whisperType, fromId, chatString)
def displayWhisperPlayer(self, playerId, chatString, whisperType):
"""
Displays the whisper message in whatever capacity makes sense.
This is separate from setWhisper so we can safely call it by
name from within setWhisper and expect the derived function to
override it.
"""
print "WhisperPlayer type %s from %s: %s" % (whisperType, playerId, chatString)
### setWhisperSC ###
def whisperSCTo(self, msgIndex, sendToId, toPlayer):
"""
Sends a speedchat whisper message to the indicated
avatar/player.
"""
if toPlayer:
base.cr.playerFriendsManager.sendSCWhisper(sendToId, msgIndex)
else:
messenger.send("wakeup")
self.sendUpdate("setWhisperSCFrom", [self.doId, msgIndex], sendToId)
def setWhisperSCFrom(self, fromId, msgIndex):
"""
Receive and decode the SpeedChat message.
"""
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if base.cr.avatarFriendsManager.checkIgnored(fromId):
# We're ignoring this jerk.
self.d_setWhisperIgnored(fromId)
return
if fromId in self.ignoreList:
# We're ignoring this jerk.
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTQuickTalker)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, fromId)
### setWhisperSCCustom ###
def whisperSCCustomTo(self, msgIndex, sendToId, toPlayer):
"""
Sends a speedchat whisper message to the indicated
toon, prefixed with our own name.
"""
if toPlayer:
base.cr.playerFriendsManager.sendSCCustomWhisper(sendToId, msgIndex)
return
messenger.send("wakeup")
self.sendUpdate("setWhisperSCCustomFrom", [self.doId, msgIndex],
sendToId)
def _isValidWhisperSource(self, source):
return True
def setWhisperSCCustomFrom(self, fromId, msgIndex):
"""
Receive and decode the SC message.
"""
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if not self._isValidWhisperSource(handle):
self.notify.warning('displayWhisper from non-toon %s' % fromId)
return
# new ignore list is handled by the Friends manager's, there are now two types, avatar and player.
if base.cr.avatarFriendsManager.checkIgnored(fromId):
# We're ignoring this jerk.
self.d_setWhisperIgnored(fromId)
return
if fromId in self.ignoreList:
# We're ignoring this jerk.
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTQuickTalker)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, fromId)
### setWhisperSCEmote ###
def whisperSCEmoteTo(self, emoteId, sendToId, toPlayer):
"""
Sends a speedchat whisper message to the indicated
toon, prefixed with our own name.
"""
print("whisperSCEmoteTo %s %s %s" % (emoteId, sendToId, toPlayer))
if toPlayer:
base.cr.playerFriendsManager.sendSCEmoteWhisper(sendToId, emoteId)
return
messenger.send("wakeup")
self.sendUpdate("setWhisperSCEmoteFrom", [self.doId, emoteId],
sendToId)
def setWhisperSCEmoteFrom(self, fromId, emoteId):
"""
Receive and decode the SC message.
"""
handle = base.cr.identifyAvatar(fromId)
if handle == None:
return
if base.cr.avatarFriendsManager.checkIgnored(fromId):
# We're ignoring this jerk.
self.d_setWhisperIgnored(fromId)
return
chatString = SCDecoders.decodeSCEmoteWhisperMsg(emoteId,
handle.getName())
if chatString:
self.displayWhisper(fromId, chatString, WhisperPopup.WTEmote)
base.talkAssistant.receiveAvatarWhisperSpeedChat(TalkAssistant.SPEEDCHAT_EMOTE, emoteId, fromId)
def d_setWhisperIgnored(self, sendToId):
# Don't send this message for the time being.
# I haven't removed it completely since we may
# want to send it in the future.
# self.sendUpdate("setWhisperIgnored", [self.doId], sendToId)
pass
### setChat ###
def setChatAbsolute(self, chatString, chatFlags, dialogue = None, interrupt = 1, quiet = 0):
DistributedAvatar.DistributedAvatar.setChatAbsolute(self, chatString, chatFlags, dialogue, interrupt)
if not quiet:
pass
def b_setChat(self, chatString, chatFlags):
# Is this a magic word? All magic words begin with a ~
if (self.cr.wantMagicWords and
(len(chatString) > 0) and (chatString[0] == "~")):
# Tell the magic word manager we just said a magic word
messenger.send("magicWord", [chatString])
else:
# HACK for demo - Outgoing dirty word check. NEVER RELY ON THIS.
if base.config.GetBool('want-chatfilter-hacks',0):
if base.config.GetBool('want-chatfilter-drop-offending',0):
if badwordpy.test(chatString):
return
else:
chatString = badwordpy.scrub(chatString)
# Local
# avoid having to check if this is the local toon
messenger.send("wakeup")
self.setChatAbsolute(chatString, chatFlags)
# Distributed
self.d_setChat(chatString, chatFlags)
def d_setChat(self, chatString, chatFlags):
self.sendUpdate("setChat", [chatString, chatFlags, 0])
#self.sendUpdate("setTalk", [0, 0, chatString, []])
def setTalk(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = self.scrubTalk(chat, mods)
self.displayTalk(newText)
if base.talkAssistant.isThought(newText):
newText = base.talkAssistant.removeThoughtPrefix(newText)
base.talkAssistant.receiveThought(fromAV, avatarName, fromAC, None, newText, scrubbed)
else:
base.talkAssistant.receiveOpenTalk(fromAV, avatarName, fromAC, None, newText, scrubbed)
def setTalkWhisper(self, fromAV, fromAC, avatarName, chat, mods, flags):
newText, scrubbed = self.scrubTalk(chat, mods)
#self.displayTalk(newText)
self.displayTalkWhisper(fromAV, avatarName, chat, mods)
base.talkAssistant.receiveWhisperTalk(fromAV, avatarName, fromAC, None, self.doId, self.getName(), newText, scrubbed)
def displayTalkWhisper(self, fromId, avatarName, chatString, mods):
"""displayTalkWhisper(self, int fromId, string chatString)
Displays the whisper message in whatever capacity makes sense.
This is separate from setWhisper so we can safely call it by
name from within setWhisper and expect the derived function to
override it.
"""
print "TalkWhisper from %s: %s" % (fromId, chatString)
def scrubTalk(self, chat, mods):
"""
returns chat where the mods have been replaced with appropreiate words
this is not in chat assistant because the replacement needs to be done
by the object that speeaks them. A pirate says "arr",
a duck says "quack", etc..
"""
return chat
def setChat(self, chatString, chatFlags, DISLid):
"""setChat(self, string)
Garble the message if needed, then pass message to setChatAbsolute
"""
self.notify.error("Should call setTalk")
chatString = base.talkAssistant.whiteListFilterMessage(chatString)
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
# We're ignoring this jerk.
return
# if we don't have chat permission, garble the chat message
if base.localAvatar.garbleChat and (not self.isUnderstandable()):
chatString = self.chatGarbler.garble(self, chatString)
# Clear any buttons or speedchat state from the chat flags;
# both of these go through a different interface.
chatFlags &= ~(CFQuicktalker | CFPageButton | CFQuitButton)
# Also, enforce that either the speech or thought bit is set,
# and the timeout is set iff speech is set.
if (chatFlags & CFThought):
chatFlags &= ~(CFSpeech | CFTimeout)
else:
chatFlags |= (CFSpeech | CFTimeout)
self.setChatAbsolute(chatString, chatFlags)
### setSC ###
def b_setSC(self, msgIndex):
# Local
self.setSC(msgIndex)
# Distributed
self.d_setSC(msgIndex)
def d_setSC(self, msgIndex):
messenger.send("wakeup")
self.sendUpdate("setSC", [msgIndex])
def setSC(self, msgIndex):
"""
Receive and decode the SC message
"""
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
# We're ignoring this jerk.
return
if self.doId in base.localAvatar.ignoreList:
# We're ignoring this jerk.
return
chatString = SCDecoders.decodeSCStaticTextMsg(msgIndex)
if chatString:
self.setChatAbsolute(chatString,
CFSpeech | CFQuicktalker | CFTimeout, quiet = 1)
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_NORMAL, msgIndex, self.doId)
### setSCCustom ###
def b_setSCCustom(self, msgIndex):
# Local
self.setSCCustom(msgIndex)
# Distributed
self.d_setSCCustom(msgIndex)
def d_setSCCustom(self, msgIndex):
messenger.send("wakeup")
self.sendUpdate("setSCCustom", [msgIndex])
def setSCCustom(self, msgIndex):
"""
Receive and decode the SC message
"""
# new ignore list is handled by the Friends manager's, there are now two types, avatar and player.
if base.cr.avatarFriendsManager.checkIgnored(self.doId):
# We're ignoring this jerk.
return
if self.doId in base.localAvatar.ignoreList:
# We're ignoring this jerk.
return
chatString = SCDecoders.decodeSCCustomMsg(msgIndex)
if chatString:
self.setChatAbsolute(chatString,
CFSpeech | CFQuicktalker | CFTimeout)
base.talkAssistant.receiveOpenSpeedChat(TalkAssistant.SPEEDCHAT_CUSTOM, msgIndex, self.doId)
### setSCEmote ###
def b_setSCEmote(self, emoteId):
self.b_setEmoteState(emoteId,
animMultiplier=self.animMultiplier)
def d_friendsNotify(self, avId, status):
self.sendUpdate("friendsNotify", [avId, status])
def friendsNotify(self, avId, status):
"""friendsNotify(self, int32 avId, int8 status)
This message is sent by the AI to notify the client when
friends are added or removed without the client's
participation, if the client happens to be logged in.
status is one of:
1 - The indicated avatar is no longer your friend.
2 - The indicated avatar is now your "special" friend.
Other changes don't require notification, because the client
was presumably in direct control.
"""
avatar = base.cr.identifyFriend(avId)
if (avatar != None):
if (status == 1):
self.setSystemMessage(avId, OTPLocalizer.WhisperNoLongerFriend % avatar.getName())
elif (status == 2):
self.setSystemMessage(avId, OTPLocalizer.WhisperNowSpecialFriend % avatar.getName())
### teleportQuery ###
def d_teleportQuery(self, requesterId, sendToId = None):
self.sendUpdate("teleportQuery", [requesterId], sendToId)
#print("sending teleportQuery %s %s" % (requesterId, sendToId))
def teleportQuery(self, requesterId):
"""teleportQuery(self, int requesterId)
This distributed message is sent peer-to-peer from one client
who is considering teleporting to another client. When it is
received, the receiving client should send back a
teleportResponse indicating whether she is available to be
teleported to (e.g. not on a trolley or something), and if so,
where she is.
"""
# Only consider teleport requests from toons who are on our
# friends list, or who are somewhere nearby.
#print("received teleportQuery %s" % (requesterId))
#avatar = base.cr.identifyAvatar(requesterId)
avatar = base.cr.playerFriendsManager.identifyFriend(requesterId)
if avatar != None:
# new ignore list is handled by the Friends manager's, there are now two types, avatar and player.
if base.cr.avatarFriendsManager.checkIgnored(requesterId):
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId = requesterId)
return
# We're ignoring this jerk. Send back a suitable response.
if requesterId in self.ignoreList:
self.d_teleportResponse(self.doId, 2, 0, 0, 0, sendToId = requesterId)
return
# If we're in a private party and the requester isn't invited, tell
# them we're busy (ie: let them down easy, don't rub it in their face)
if hasattr(base, "distributedParty"):
if base.distributedParty.partyInfo.isPrivate:
# We need to check the guest list of this party and see if
# requesterId is on the list
if requesterId not in base.distributedParty.inviteeIds:
# Sorry, not on the list, send a try-again-later message
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId = requesterId)
return
if base.distributedParty.isPartyEnding:
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId = requesterId)
return
#print("teleport Available %s Ghost %s" % (self.__teleportAvailable, self.ghostMode))
if self.__teleportAvailable and not self.ghostMode:
# Generate a whisper message that so-and-so is teleporting
# to us.
self.setSystemMessage(requesterId, OTPLocalizer.WhisperComingToVisit % (avatar.getName()))
# We don't know where we are, so send a teleportQuery
# to someone who does. Whoever hangs a hook on this
# event will call the appropriate teleportResponse.
messenger.send('teleportQuery', [avatar, self])
return
# Generate a whisper message that so-and-so wants to
# teleport to us, but can't because we're busy. But don't
# generate more than one of these per minute or so.
if self.failedTeleportMessageOk(requesterId):
self.setSystemMessage(requesterId, OTPLocalizer.WhisperFailedVisit % (avatar.getName()))
# Send back a try-again-later message.
self.d_teleportResponse(self.doId, 0, 0, 0, 0, sendToId = requesterId)
def failedTeleportMessageOk(self, fromId):
"""failedTeleportMessageOk(self, int fromId)
Registers a failure-to-teleport attempt from the indicated
avatar. Returns true if it is ok to display this message, or
false if the message should be suppressed (because we just
recently displayed one).
"""
now = globalClock.getFrameTime()
lastTime = self.lastFailedTeleportMessage.get(fromId, None)
if lastTime != None:
elapsed = now - lastTime
if elapsed < self.TeleportFailureTimeout:
return 0
self.lastFailedTeleportMessage[fromId] = now
return 1
### teleportResponse ###
def d_teleportResponse(self, avId, available, shardId, hoodId, zoneId,
sendToId = None):
self.sendUpdate("teleportResponse", [avId, available, shardId, hoodId, zoneId], sendToId)
def teleportResponse(self, avId, available, shardId, hoodId, zoneId):
messenger.send('teleportResponse', [avId, available, shardId, hoodId, zoneId])
### teleportGiveup ###
def d_teleportGiveup(self, requesterId, sendToId = None):
self.sendUpdate("teleportGiveup", [requesterId], sendToId)
def teleportGiveup(self, requesterId):
"""teleportGiveup(self, int requesterId)
This message is sent after a client has failed to teleport
successfully to another client, probably because the target
client didn't stay put. It just pops up a whisper message to
that effect.
"""
avatar = base.cr.identifyAvatar(requesterId)
if not self._isValidWhisperSource(avatar):
self.notify.warning('teleportGiveup from non-toon %s' % requesterId)
return
if avatar != None:
self.setSystemMessage(requesterId, OTPLocalizer.WhisperGiveupVisit % (avatar.getName()))
### teleportGreeting ###
# This message is sent on completion of teleport, to set up the
# automatic "Hi, so-and-so" chat balloon. We can't use setChat
# because that gets garbled for speedchat-only clients.
def b_teleportGreeting(self, avId):
self.d_teleportGreeting(avId)
self.teleportGreeting(avId)
def d_teleportGreeting(self, avId):
self.sendUpdate("teleportGreeting", [avId])
def teleportGreeting(self, avId):
# Normally, the greeting will be issued to someone who we have
# just teleported to, and is therefore in the same zone with
# us. If this is so, it is easy to determine what the greeted
# toon's actual name is; otherwise, something went wrong
# (maybe our greeted toon just left!) and we can simply ignore
# the message.
avatar = base.cr.getDo(avId)
if isinstance(avatar, Avatar.Avatar):
self.setChatAbsolute(OTPLocalizer.TeleportGreeting % (
avatar.getName()), CFSpeech | CFTimeout)
elif avatar is not None:
self.notify.warning(
'got teleportGreeting from %s referencing non-toon %s' % (
self.doId, avId))
### Teleport support functions ###
def setTeleportAvailable(self, available):
"""setTeleportAvailable(self, bool available)
Sets the 'teleportAvailable' flag. When this is true, the
client is deemed to be available to be teleported to, and
someone should be listening to teleportQuery messages from the
messenger. When it is false, teleport queries from nearby
toons will automatically be returned with a false response
without generating a teleportQuery message.
"""
self.__teleportAvailable = available
def getTeleportAvailable(self):
return self.__teleportAvailable
def getFriendsList(self):
return self.friendsList
def setFriendsList(self, friendsList):
self.oldFriendsList = self.friendsList
self.friendsList = friendsList
self.timeFriendsListChanged = globalClock.getFrameTime()
assert self.notify.debug("setting friends list to %s" % self.friendsList)
# We want to throw a special event whenever the LocalToon's
# friends list changes, although not when just any
# DistributedToon's friends list changes. It would be cleaner
# to define this special behavior in LocalToon.py, but as it
# happens, it won't get called there because of the way
# ClientDistUpdate.py works.
# Fortunately, this method will *only* get called for
# LocalToon, and not for any of the other DistributedToons.
# So we can get away with putting this here.
messenger.send('friendsListChanged')
# When our friends list changes, the set of other avatars we
# can understand might also change.
Avatar.reconsiderAllUnderstandable()
def setDISLname(self, name):
self.DISLname = name
def setDISLid(self, id):
self.DISLid = id
def setAutoRun(self, value):
self.autoRun = value
def getAutoRun(self):
return self.autoRun

View file

@ -0,0 +1,158 @@
from direct.showbase import GarbageReport
from otp.ai.AIBaseGlobal import *
from otp.avatar import DistributedAvatarAI
from otp.avatar import PlayerBase
from otp.otpbase import OTPGlobals
class DistributedPlayerAI(DistributedAvatarAI.DistributedAvatarAI,
PlayerBase.PlayerBase):
def __init__(self, air):
DistributedAvatarAI.DistributedAvatarAI.__init__(self, air)
PlayerBase.PlayerBase.__init__(self)
self.friendsList = []
if __dev__:
def generate(self):
self._sentExitServerEvent = False
DistributedAvatarAI.DistributedAvatarAI.generate(self)
def announceGenerate(self):
DistributedAvatarAI.DistributedAvatarAI.announceGenerate(self)
self._doPlayerEnter()
def _announceArrival(self):
self.sendUpdate('arrivedOnDistrict', [self.air.districtId])
def _announceExit(self):
# clear out the 'arrivedOnDistrict' field
self.sendUpdate('arrivedOnDistrict', [0])
def _sendExitServerEvent(self):
"""call this in your delete() function. This would be an
override of delete(), but player classes typically use
multiple inheritance, and some other base class gets to
call down the chain to DistributedObjectAI before this
class gets a chance, and self.air & self.doId are removed
in the first call to DistributedObjectAI.delete(). Better
would be reference counting calls to generate() and delete()
in base classes that appear more than once in a class'
inheritance heirarchy"""
self.air.writeServerEvent('avatarExit', self.doId, '')
if __dev__:
self._sentExitServerEvent = True
def delete(self):
if __dev__:
# make sure _sendExitServerEvent() was called
assert self._sentExitServerEvent
del self._sentExitServerEvent
self._doPlayerExit()
if __dev__:
GarbageReport.checkForGarbageLeaks()
DistributedAvatarAI.DistributedAvatarAI.delete(self)
def isPlayerControlled(self):
return True
def setLocation(self, parentId, zoneId, teleport=0):
DistributedAvatarAI.DistributedAvatarAI.setLocation(self, parentId, zoneId, teleport)
if self.isPlayerControlled():
# hmm, did this come from a hacker trying to get somewhere they shouldn't be?
if not self.air._isValidPlayerLocation(parentId, zoneId):
self.notify.info('booting player %s for doing setLocation to (%s, %s)' % (
self.doId, parentId, zoneId))
self.air.writeServerEvent('suspicious', self.doId,
'invalid setLocation: (%s, %s)' % (parentId, zoneId))
self.requestDelete()
def _doPlayerEnter(self):
self.incrementPopulation()
self._announceArrival()
def _doPlayerExit(self):
self._announceExit()
self.decrementPopulation()
# override if you don't want to affect the population count for a
# particular PlayerAI
def incrementPopulation(self):
self.air.incrementPopulation()
def decrementPopulation(self):
# use simbase in case we've already deleted self.air
simbase.air.decrementPopulation()
def b_setChat(self, chatString, chatFlags):
# Local
self.setChat(chatString, chatFlags)
# Distributed
self.d_setChat(chatString, chatFlags)
def d_setChat(self, chatString, chatFlags):
self.sendUpdate("setChat", [chatString, chatFlags])
def setChat(self, chatString, chatFlags):
# I guess on the AI side there is nothing to do here
pass
def d_setMaxHp(self, maxHp):
DistributedAvatarAI.DistributedAvatarAI.d_setMaxHp(self, maxHp)
self.air.writeServerEvent('setMaxHp', self.doId, '%s' % maxHp)
def d_setSystemMessage(self, aboutId, chatString):
self.sendUpdate("setSystemMessage", [aboutId, chatString])
def d_setCommonChatFlags(self, flags):
self.sendUpdate("setCommonChatFlags", [flags])
def setCommonChatFlags(self, flags):
pass
def d_friendsNotify(self, avId, status):
self.sendUpdate("friendsNotify", [avId, status])
def friendsNotify(self, avId, status):
pass
def setAccountName(self, accountName):
self.accountName = accountName
def getAccountName(self):
return self.accountName
def setDISLid(self, id):
self.DISLid = id
def d_setFriendsList(self, friendsList):
self.sendUpdate("setFriendsList", [friendsList])
def setFriendsList(self, friendsList):
self.friendsList = friendsList
self.notify.debug("setting friends list to %s" % self.friendsList)
def getFriendsList(self):
return self.friendsList
def extendFriendsList(self, friendId, friendCode):
# This is called only by the friend manager when a new friend
# transaction is successfully completed. Its purpose is
# simply to update the AI's own copy of the avatar's friends
# list, mainly so that the quest manager can reliably know
# if the avatar has any friends.
# First, see if we already had this friend.
for i in range(len(self.friendsList)):
friendPair = self.friendsList[i]
if friendPair[0] == friendId:
# We did. Update the code.
self.friendsList[i] = (friendId, friendCode)
return
# We didn't already have this friend; tack it on.
self.friendsList.append((friendId, friendCode))
# Note that if an avatar *breaks* a friendship, the AI never
# hears about it. So our friends list will not be 100%
# up-to-date, but it will at least be good enough for the
# quest manager.

29
otp/src/avatar/Emote.py Normal file
View file

@ -0,0 +1,29 @@
from otp.otpbase import OTPLocalizer
import types
class Emote:
EmoteClear = -1
EmoteEnableStateChanged = 'EmoteEnableStateChanged'
# Emote data is stored in the order it appears in the SpeedChat m
# The integer stored is the reference count to the Emote. If the
# count goes above zero, it means that the emote is disabled. Fo
# a minigame might increment the reference count if it wants to e
# disable emotes.
def __init__(self):
self.emoteFunc = None
def isEnabled(self, index):
# find the emotes index if we are given a string
if isinstance(index, types.StringType):
index = OTPLocalizer.EmoteFuncDict[index]
if self.emoteFunc == None:
return 0
elif self.emoteFunc[index][1] == 0:
return 1
return 0
globalEmote = None

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
class PlayerBase:
# player code shared by AI & client
def __init__(self):
self.gmState = False
pass
def atLocation(self, locationId):
return True
def getLocation(self):
# return a list of locationIds, starting from general location
# (i.e. 'Pirates') down to specific location (i.e. jungle ID)
return []
def setAsGM(self, state):
""" Toggle GM privilages """
self.gmState = state
def isGM(self):
return self.gmState

View file

@ -0,0 +1,159 @@
from pandac.PandaModules import *
from direct.showbase.DirectObject import DirectObject
from otp.otpbase import OTPGlobals
class PositionExaminer(DirectObject, NodePath):
"""
This class defines an object that can be used to examine a point in
space for suitability for standing on. It's used, for instance,
to choose a particular point to Go to when you Goto a friend.
A valid destination point is one that (a) has a ground whose
height is not too far from our target height, (b) is not already
occupied, and (c) is not behind a wall.
"""
def __init__(self):
try:
self.__initialized
return
except:
self.__initialized = 1
# initialize our NodePath essence
NodePath.__init__(self, hidden.attachNewNode('PositionExaminer'))
# Set up the collison ray. This is a ray cast from the head
# height down to detect floor polygons. It will tell us the
# height of the floor at our proposed position.
self.cRay = CollisionRay(0.0, 0.0, 6.0, 0.0, 0.0, -1.0)
self.cRayNode = CollisionNode('cRayNode')
self.cRayNode.addSolid(self.cRay)
self.cRayNodePath = self.attachNewNode(self.cRayNode)
self.cRayNodePath.hide()
self.cRayBitMask = OTPGlobals.FloorBitmask
self.cRayNode.setFromCollideMask(self.cRayBitMask)
self.cRayNode.setIntoCollideMask(BitMask32.allOff())
# Set up the collision sphere. This is a sphere on the ground
# that exactly matches the position and size of an avatar's
# sphere. It will tell us if our proposed position is occupied
# by anyone else.
self.cSphere = CollisionSphere(0.0, 0.0, 0.0, 1.5)
self.cSphereNode = CollisionNode('cSphereNode')
self.cSphereNode.addSolid(self.cSphere)
self.cSphereNodePath = self.attachNewNode(self.cSphereNode)
self.cSphereNodePath.hide()
self.cSphereBitMask = OTPGlobals.WallBitmask
self.cSphereNode.setFromCollideMask(self.cSphereBitMask)
self.cSphereNode.setIntoCollideMask(BitMask32.allOff())
# Set up the camera obstruction test line segment. This is a
# line segment from the proposed position point to our target
# position, to ensure that we are not behind a wall.
self.ccLine = CollisionSegment(0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
self.ccLineNode = CollisionNode('ccLineNode')
self.ccLineNode.addSolid(self.ccLine)
self.ccLineNodePath = self.attachNewNode(self.ccLineNode)
self.ccLineNodePath.hide()
self.ccLineBitMask = OTPGlobals.CameraBitmask
self.ccLineNode.setFromCollideMask(self.ccLineBitMask)
self.ccLineNode.setIntoCollideMask(BitMask32.allOff())
# Now the gnarly part. Each of the above colliders must have
# a separate traverser, so we can independently activate each
# one and query the results.
self.cRayTrav = CollisionTraverser("PositionExaminer.cRayTrav")
self.cRayTrav.setRespectPrevTransform(False)
self.cRayQueue = CollisionHandlerQueue()
self.cRayTrav.addCollider(self.cRayNodePath, self.cRayQueue)
self.cSphereTrav = CollisionTraverser("PositionExaminer.cSphereTrav")
self.cSphereTrav.setRespectPrevTransform(False)
self.cSphereQueue = CollisionHandlerQueue()
self.cSphereTrav.addCollider(self.cSphereNodePath, self.cSphereQueue)
self.ccLineTrav = CollisionTraverser("PositionExaminer.ccLineTrav")
self.ccLineTrav.setRespectPrevTransform(False)
self.ccLineQueue = CollisionHandlerQueue()
self.ccLineTrav.addCollider(self.ccLineNodePath, self.ccLineQueue)
def delete(self):
del self.cRay
del self.cRayNode
self.cRayNodePath.removeNode()
del self.cRayNodePath
del self.cSphere
del self.cSphereNode
self.cSphereNodePath.removeNode()
del self.cSphereNodePath
del self.ccLine
del self.ccLineNode
self.ccLineNodePath.removeNode()
del self.ccLineNodePath
del self.cRayTrav
del self.cRayQueue
del self.cSphereTrav
del self.cSphereQueue
del self.ccLineTrav
del self.ccLineQueue
def consider(self, node, pos, eyeHeight):
"""consider(self, NodePath node, Point3 pos, eyeHeight)
Considers the indicated point, relative to the given NodePath.
The point must have a floor polygon that's within a foot or
two of the NodePath's origin, there must be no one standing
near the point, and it must have a clear line-of-sight to the
NodePath's origin.
Returns the actual point to stand if all these conditions are
met, or None if one of them fails.
"""
self.reparentTo(node)
self.setPos(pos)
result = None
# First, check that we have a good floor here.
self.cRayTrav.traverse(render)
if self.cRayQueue.getNumEntries() != 0:
# Ok, we have a floor. Choose the highest of the possibly
# several floors we're over.
self.cRayQueue.sortEntries()
floorPoint = self.cRayQueue.getEntry(0).getSurfacePoint(self.cRayNodePath)
if abs(floorPoint[2]) <= 4.0:
# And the floor is not too high or too low.
pos += floorPoint
self.setPos(pos)
# Now check that no one else is standing right here.
self.cSphereTrav.traverse(render)
if self.cSphereQueue.getNumEntries() == 0:
# No one's standing there, and there's no wall.
# Now check that we have a clear line-of-sight.
self.ccLine.setPointA(0, 0, eyeHeight)
self.ccLine.setPointB(-pos[0], -pos[1], eyeHeight)
self.ccLineTrav.traverse(render)
if self.ccLineQueue.getNumEntries() == 0:
# We're not behind a wall or anything.
result = pos
self.reparentTo(hidden)
self.cRayQueue.clearEntries()
self.cSphereQueue.clearEntries()
self.ccLineQueue.clearEntries()
return result

View file

@ -0,0 +1,198 @@
from pandac.PandaModules import *
from pandac.PandaModules import *
from direct.directnotify import DirectNotifyGlobal
from direct.showbase.ShadowPlacer import ShadowPlacer
from otp.otpbase import OTPGlobals
# This global variable will be set true or false according to whether
# all avatar's drop shadows should be made visible, by the
# TimeOfDayManager (which currently manages projected shadows).
# Always change its state via this function, instead of monkeying with
# it directly.
globalDropShadowFlag = 1
def setGlobalDropShadowFlag(flag):
global globalDropShadowFlag
if flag != globalDropShadowFlag:
globalDropShadowFlag = flag
messenger.send('globalDropShadowFlagChanged')
# A similar trick to control the global gray level of the drop shadows.
globalDropShadowGrayLevel = 0.5
def setGlobalDropShadowGrayLevel(grayLevel):
global globalDropShadowGrayLevel
if grayLevel != globalDropShadowGrayLevel:
globalDropShadowGrayLevel = grayLevel
messenger.send('globalDropShadowGrayLevelChanged')
# I made this inherit from DirectObject so that non-distributed things can cast shadows
class ShadowCaster:
notify = DirectNotifyGlobal.directNotify.newCategory("ShadowCaster")
#notify.setDebug(1)
def __init__(self, squareShadow = False):
assert self.notify.debugStateCall(self)
# some shadow initialization stuff
if squareShadow:
self.shadowFileName = "phase_3/models/props/square_drop_shadow"
else:
self.shadowFileName = "phase_3/models/props/drop_shadow"
self.dropShadow = None
self.shadowPlacer = None
self.activeShadow = 0
self.wantsActive = 1
self.storedActiveState = 0
# Only create these hooks if we're running a game that cares
# about them.
if hasattr(base,"wantDynamicShadows") and base.wantDynamicShadows:
messenger.accept('globalDropShadowFlagChanged', self, self.__globalDropShadowFlagChanged)
messenger.accept('globalDropShadowGrayLevelChanged', self, self.__globalDropShadowGrayLevelChanged)
def delete(self):
assert self.notify.debugStateCall(self)
# Only remove these hooks if we're running a game that cares
# about them.
if hasattr(base,"wantDynamicShadows") and base.wantDynamicShadows:
messenger.ignore('globalDropShadowFlagChanged', self)
messenger.ignore('globalDropShadowGrayLevelChanged', self)
self.deleteDropShadow()
self.shadowJoint = None
def initializeDropShadow(self, hasGeomNode=True):
"""
Load up and arrange the drop shadow
"""
assert self.notify.debugStateCall(self)
# First, protect this function from being called twice by
# removing the old ones first.
self.deleteDropShadow()
# This will be used by the shadow system to identify things
# that might want to have projected shadows drawn.
if hasGeomNode:
self.getGeomNode().setTag('cam', 'caster')
# make the object float above the shadow slightly
# not necessarily a good idea for all avatars
#self.getGeomNode().setZ(0.025)
# load and prep the drop shadow
dropShadow = loader.loadModel(self.shadowFileName)
dropShadow.setScale(0.4) # Slightly smaller to compensate for billboard
dropShadow.flattenMedium()
dropShadow.setBillboardAxis(2) # slide the shadow towards the camera
dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1) # override of 1 to prevent avatar.setColor() from affecting shadows.
self.shadowPlacer = ShadowPlacer(
base.shadowTrav, dropShadow,
OTPGlobals.WallBitmask, OTPGlobals.FloorBitmask)
self.dropShadow = dropShadow
if not globalDropShadowFlag:
self.dropShadow.hide()
if self.getShadowJoint():
dropShadow.reparentTo(self.getShadowJoint())
else:
self.dropShadow.hide()
# Set the state of the shadow placers (in case someone set the
# value before now):
self.setActiveShadow(self.wantsActive)
self.__globalDropShadowFlagChanged()
self.__globalDropShadowGrayLevelChanged()
def update(self):
"""This method is meant to be overriden."""
# Toontown doesn't have self.update() for all shadowcasters
# but initializeDropShadow calls it, so this prevents a crash.
pass
def deleteDropShadow(self):
"""
Lose the drop shadows
"""
assert self.notify.debugStateCall(self)
if self.shadowPlacer:
self.shadowPlacer.delete()
self.shadowPlacer = None
if self.dropShadow:
self.dropShadow.removeNode()
self.dropShadow = None
def setActiveShadow(self, isActive=1):
"""
Turn the shadow placement on or off.
"""
assert self.notify.debugStateCall(self)
isActive = isActive and self.wantsActive
if(not globalDropShadowFlag):
self.storedActiveState = isActive
# changed logic to prevent crash (test remark 13203) - grw
if self.shadowPlacer != None:
isActive = isActive and globalDropShadowFlag
if self.activeShadow != isActive:
self.activeShadow = isActive
if isActive:
self.shadowPlacer.on()
else:
self.shadowPlacer.off()
def setShadowHeight(self, shadowHeight):
"""
Places the shadow at a particular height below the avatar (in
effect, asserting that the avatar is shadowHeight feet above
the ground).
This is only useful when the active shadow is disabled via
setActiveShadow(0).
"""
assert self.notify.debugStateCall(self)
if self.dropShadow:
self.dropShadow.setZ(-shadowHeight)
def getShadowJoint(self):
assert self.notify.debugStateCall(self)
if hasattr(self, "shadowJoint"):
return self.shadowJoint
shadowJoint = self.find('**/attachShadow')
if shadowJoint.isEmpty():
# We make a fresh NodePath that refers to the same node as
# self, rather than assigning self directly--this will
# prevent a cyclic Python reference.
self.shadowJoint = NodePath(self)
else:
self.shadowJoint = shadowJoint
return self.shadowJoint
def hideShadow(self):
assert self.notify.debugStateCall(self)
self.dropShadow.hide()
def showShadow(self):
assert self.notify.debugStateCall(self)
if not globalDropShadowFlag:
self.dropShadow.hide()
else:
self.dropShadow.show()
def __globalDropShadowFlagChanged(self):
if (self.dropShadow != None):
if(globalDropShadowFlag == 0):
if(self.activeShadow == 1):
self.storedActiveState = 1
self.setActiveShadow(0)
elif(self.activeShadow == 0):
self.setActiveShadow(1)
self.showShadow()
def __globalDropShadowGrayLevelChanged(self):
if (self.dropShadow != None):
self.dropShadow.setColor(0.0, 0.0, 0.0, globalDropShadowGrayLevel, 1)

View file

@ -0,0 +1,3 @@
// For now, since we are not installing Python files, this file can
// remain empty.

View file

4
otp/src/chat/.cvsignore Normal file
View file

@ -0,0 +1,4 @@
.cvsignore
Makefile
*.pyc
pp.dep

View file

@ -0,0 +1,56 @@
"""ChatGarbler module: conatins the ChatGarbler class"""
import string
#import whrandom
import random
from otp.otpbase import OTPLocalizer
class ChatGarbler:
"""ChatGarbler class: contains methods to convert chat messages
to animal sounds"""
def garble(self, avatar, message):
"""garble(self, Avatar, string)
Replace a chat message with a series of animal sounds
based on the toon's animal type
Algorithm completely disregards original message to
prohibit any sort of meaningful communication
"""
newMessage = ""
numWords = random.randint(1, 7)
wordlist = OTPLocalizer.ChatGarblerDefault
for i in range(1, numWords+1):
wordIndex = random.randint(0, len(wordlist)-1)
newMessage = newMessage + wordlist[wordIndex]
if (i < numWords):
newMessage = newMessage + " "
return newMessage
def garbleSingle(self, avatar, message):
"""garble(self, Avatar, string)
Replace a chat message with a series of animal sounds
based on the toon's animal type
Algorithm completely disregards original message to
prohibit any sort of meaningful communication
"""
newMessage = ""
numWords = 1
wordlist = OTPLocalizer.ChatGarblerDefault
for i in range(1, numWords+1):
wordIndex = random.randint(0, len(wordlist)-1)
newMessage = newMessage + wordlist[wordIndex]
if (i < numWords):
newMessage = newMessage + " "
return newMessage

View file

@ -0,0 +1,77 @@
import string
NORMAL_CHAT = 1
WHISPER_CHAT = 2
GUILD_CHAT = 3
CREW_CHAT = 4
SHIPPVP_CHAT = 5
# ERROR CODES
ERROR_NONE = None
ERROR_NO_OPEN_CHAT = 1
ERROR_NOT_FRIENDS = 2
ERROR_NO_RECEIVER = 3
ERROR_NO_GUILD_CHAT = 4
ERROR_NO_CREW_CHAT = 5
ERROR_NO_SHIPPVP_CHAT = 6
#CHAT TYPES
TYPEDCHAT = 0
SPEEDCHAT_NORMAL = 1
SPEEDCHAT_EMOTE = 2
SPEEDCHAT_CUSTOM = 3
SYSTEMCHAT = 4
GAMECHAT = 5
GUILDCHAT = 6
PARTYCHAT = 7
SPEEDCHAT_QUEST = 8
FRIEND_UPDATE = 9
CREW_UPDATE = 10
GUILD_UPDATE = 11
AVATAR_UNAVAILABLE = 12
SHIPPVPCHAT = 13
GMCHAT = 14
# the events are hierarchical; when a
# speedchat msg is picked, for instance, the
# following events will be sent:
# 'ChatEvent', 'SCChatEvent'
ChatEvent = 'ChatEvent'
NormalChatEvent = 'NormalChatEvent'
SCChatEvent = 'SCChatEvent'
SCCustomChatEvent = 'SCCustomChatEvent'
SCEmoteChatEvent = 'SCEmoteChatEvent'
SCQuestEvent = 'SCQuestEvent'
OnScreen = 0
OffScreen = 1
Thought = 2
ThoughtPrefix = '.'
# thought methods
def isThought(message):
"""
message is a string.
Return 1 if the given string contains the thought prefix,
Return 0 otherwise
"""
if (len(message) == 0):
# empty string cannot be a thought
return 0
elif (string.find(message, ThoughtPrefix, 0,
len(ThoughtPrefix)) >= 0):
return 1
else:
return 0
def removeThoughtPrefix(message):
"""
message is a string.
Return the string with the thought prefix removed
"""
if (isThought(message)):
return message[len(ThoughtPrefix):]
else:
return message

View file

@ -0,0 +1,204 @@
"""ChatInputNormal module: contains the ChatInputNormal class"""
from direct.showbase import DirectObject
from otp.otpbase import OTPGlobals
import sys
from direct.gui.DirectGui import *
from pandac.PandaModules import *
from otp.otpbase import OTPLocalizer
class ChatInputNormal(DirectObject.DirectObject):
"""ChatInputNormal class: controls the chat input bubble, and handles
chat message construction"""
# This will hold the local namespace we evaluate '>chat' messages
# within.
ExecNamespace = None
# special methods
def __init__(self, chatMgr):
self.chatMgr = chatMgr
self.normalPos = Vec3(-1.083, 0, 0.804)
self.whisperPos = Vec3(0.0, 0, 0.71)
self.whisperAvatarName = None
self.whisperAvatarId = None
self.toPlayer = 0
wantHistory = 0
if __dev__:
wantHistory = 1
self.wantHistory = base.config.GetBool('want-chat-history', wantHistory)
self.history = ['']
self.historySize = base.config.GetInt('chat-history-size', 10)
self.historyIndex = 0
# It is up to a derived class, like TTChatInputNormal, to
# define self.chatFrame, self.chatButton, self.cancelButton,
# and self.whisperLabel.
def typeCallback(self, extraArgs):
messenger.send('enterNormalChat')
def delete(self):
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
self.chatFrame.destroy()
del self.chatFrame
del self.chatButton
del self.cancelButton
del self.chatEntry
del self.whisperLabel
del self.chatMgr
def activateByData(self, whisperAvatarId = None, toPlayer = 0):
self.toPlayer = toPlayer
self.whisperAvatarId = whisperAvatarId
self.whisperAvatarName = base.talkAssistant.findName(self.whisperAvatarId, self.toPlayer)
if self.whisperAvatarId:
self.chatFrame.setPos(self.whisperPos)
self.whisperLabel["text"] = (OTPLocalizer.ChatInputWhisperLabel %
(self.whisperAvatarName))
self.whisperLabel.show()
else:
self.chatFrame.setPos(self.normalPos)
self.whisperLabel.hide()
self.chatEntry['focus'] = 1
self.chatFrame.show()
if self.wantHistory:
self.accept('arrow_up-up', self.getPrevHistory)
self.accept('arrow_down-up', self.getNextHistory)
def deactivate(self):
self.chatEntry.set("")
self.chatEntry['focus'] = 0
self.chatFrame.hide()
self.whisperLabel.hide()
base.win.closeIme()
self.ignore('arrow_up-up')
self.ignore('arrow_down-up')
def checkForOverRide(self):
#ChatInputNormal likes to intercept other direct entries
#too much was hard wired to the chatManagar so I'm adding a final stage override - JML
return False
def sendChat(self, text):
"""
Send the text from the entry
"""
if self.checkForOverRide():
self.chatEntry.enterText("")
return
# Done for now, go away
self.deactivate()
self.chatMgr.fsm.request("mainMenu")
# Filter out empty string
if text:
if self.toPlayer:
if self.whisperAvatarId:
#base.cr.playerFriendsManager.sendWhisper(self.whisperAvatarId, text)
#base.chatAssistant.sendPlayerWhisperTypedChat(text, self.whisperAvatarId)
self.whisperAvatarName = None
self.whisperAvatarId = None
self.toPlayer = 0
elif self.whisperAvatarId:
self.chatMgr.sendWhisperString(text, self.whisperAvatarId)
self.whisperAvatarName = None
self.whisperAvatarId = None
else:
if self.chatMgr.execChat:
# Exec a python command
if (text[0] == '>'):
text = self.__execMessage(text[1:])
base.localAvatar.setChatAbsolute(text, CFSpeech | CFTimeout)
return
base.talkAssistant.sendOpenTalk(text)
if self.wantHistory:
self.addToHistory(text)
def chatOverflow(self, overflowText):
"""
When the user types too many lines of text, an event gets thrown
which calls this function. Right now it just sends the text just
as if you hit return to complete the sentence.
"""
self.sendChat(self.chatEntry.get())
def __execMessage(self, message):
if not ChatInputNormal.ExecNamespace:
# Import some useful variables into the ExecNamespace initially.
ChatInputNormal.ExecNamespace = { }
exec 'from pandac.PandaModules import *' in globals(), self.ExecNamespace
self.importExecNamespace()
# Now try to evaluate the expression using ChatInputNormal.ExecNamespace as
# the local namespace.
try:
return str(eval(message, globals(), ChatInputNormal.ExecNamespace))
except SyntaxError:
# Maybe it's only a statement, like "x = 1", or
# "import math". These aren't expressions, so eval()
# fails, but they can be exec'ed.
try:
exec message in globals(), ChatInputNormal.ExecNamespace
return 'ok'
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
except:
exception = sys.exc_info()[0]
extraInfo = sys.exc_info()[1]
if extraInfo:
return str(extraInfo)
else:
return str(exception)
# button event handlers
def cancelButtonPressed(self):
self.chatEntry.set("")
self.chatMgr.fsm.request("mainMenu")
def chatButtonPressed(self):
self.sendChat(self.chatEntry.get())
def importExecNamespace(self):
# Derived classes should take advantage of this hook to import
# useful variables into the chat namespace for developer
# access.
pass
def addToHistory(self, text):
self.history = [text] + self.history[:self.historySize-1]
self.historyIndex = 0
def getPrevHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex += 1
self.historyIndex %= len(self.history)
def getNextHistory(self):
self.chatEntry.set(self.history[self.historyIndex])
self.historyIndex -= 1
self.historyIndex %= len(self.history)
def setPos(self, posX, posY = None, posZ = None):
if posX and posY and posZ:
self.chatFrame.setPos(posX,posY,posZ)
else:
self.chatFrame.setPos(posX)

Some files were not shown because too many files have changed in this diff Show more