示例#1
0
文件: CBMesh.cs 项目: dvochin/Scripts
    public string _sNameCBodyInstanceMember; // The base part of the name (without suffix)

    #endregion Fields

    #region Methods

    //---------------------------------------------------------------------------	INIT
    //###SOON: Redo the crappy static create to just create component with a separate Initialize() with the proper arguments
    public static CBMesh Create(GameObject oBMeshGO, CBodyBase oBodyBase, string sNameCBodyInstanceMember, Type oTypeBMesh, Boolean bKeepBlenderShare = false)
    {
        //===== Important static function that reads a Blender mesh definition stream and create the requested CBMesh-derived entity on the provided gameObject node =====

        //=== Create the game object that will host our component ===
        if (oBMeshGO == null) {                     // When CBody or test meshes are creating itself this will be set, null for rim and softbody parts.  ###WEAK!!!
            oBMeshGO = new GameObject(sNameCBodyInstanceMember, oTypeBMesh);        // If we're here it means we're rim or a body part.  Create a new game object...		####DEV ####NOW: Name problem here!
            oBMeshGO.transform.parent = oBodyBase._oMeshMorphResult.transform;           //... Parent it to the body if specified (body is always specified for rim or body parts)
        }

        //=== Create our component (of the requested type) from the above-created game object ===
        CBMesh oBMesh = (CBMesh)CUtility.FindOrCreateComponent(oBMeshGO.transform, oTypeBMesh);
        oBMesh._oBodyBase = oBodyBase;									// Push-in some important args manually (so we don't have to push them in OnDeserializeFromBlender()
        oBMesh._sNameCBodyInstanceMember = sNameCBodyInstanceMember;
        oBMesh.gameObject.name = oBMesh._sNameCBodyInstanceMember;			//###DESIGN#11!!!  IMPROVE THIS CRAPPY Node name!!  Give Unity node the 'Blender node name (i.e. not path to instance variable string!)
        oBMesh._bKeepBlenderShare = bKeepBlenderShare;

        //=== Obtain the name of the Blender mesh object from the data-member of Blender's CBody class we're paired to ===
        string sCBodyDataMember = oBodyBase._sBlenderInstancePath_CBodyBase + sNameCBodyInstanceMember;			// Fully-qualified path to the CBody data member currently pointing to the mesh we need.
        oBMesh._sNameBlenderMesh = CGame.gBL_SendCmd("CBody", sCBodyDataMember + ".GetName()");                              // Store the name of the Blender object holding the mesh so we can directly access.
        oBMesh.OnDeserializeFromBlender();				// Fully deserialize the mesh from Blender.  (Virtual call that cascades accross several classes in order)
        oBMesh.FinishIntialization();                 //###DESIGN ###CHECK?

        return oBMesh;
    }
示例#2
0
    Transform _oWatchBone; // Bone position we watch from our owning body to 'autotune' cloth simulation parameters so cloth stays on body during rapid movement (e.g. pose changing)

    #endregion Fields

    #region Methods

    public static CBCloth Create(CBodyBase oBodyBase, string sNameCloth, string sClothType, string sNameClothSrc, string sVertGrp_ClothSkinArea)
    {
        // Static function override from CBMesh::Create() to route Blender request to Body Col module and deserialize its additional information for the local creation of a CBBodyColCloth
        string sBodyID = "CBodyBase_GetBodyBase(" + oBodyBase._nBodyID.ToString() + ").";
        CBCloth.s_sNameClothSrc_HACK = "aCloths['" + sNameCloth + "']";
        CGame.gBL_SendCmd("CBody", sBodyID + "CreateCloth('" + sNameCloth + "', '" + sClothType + "', '" + sNameClothSrc + "', '" + sVertGrp_ClothSkinArea + "')");      // Create the Blender-side CCloth entity to service our requests
        //CGame.gBL_SendCmd("CBody", sBodyID + CBCloth.s_sNameClothSrc_HACK + ".UpdateCutterCurves()");
        //CGame.gBL_SendCmd("CBody", sBodyID + CBCloth.s_sNameClothSrc_HACK + ".CutClothWithCutterCurves()");
        CGame.gBL_SendCmd("CBody", sBodyID + CBCloth.s_sNameClothSrc_HACK + ".PrepareClothForGame()");		//###IMPROVE#13!!  Damn period before... make consistent!!
        CBCloth oBCloth = (CBCloth)CBMesh.Create(null, oBodyBase, "." + CBCloth.s_sNameClothSrc_HACK + ".oMeshClothSimulated", typeof(CBCloth));		// Obtain the simulated-part of the cloth that was created in call above
        //####IDEA: Modify static creation by first creating instance, stuffing it with custom data and feeding instance in Create to be filled in!
        return oBCloth;
    }
示例#3
0
文件: CBody.cs 项目: dvochin/Scripts
    public CBody(CBodyBase oBodyBase)
    {
        //###NOW#11
        _oBodyBase = oBodyBase;
        _oBodyBase._oBody = this;           //###WEAK#13: Convenience early-set of our instance into owning parent.  Needed as some of init code needs to access us from our parent! ###DESIGN!
        _oBodySkinnedMeshGO_HACK = new GameObject("RuntimeBody");       // Create the game object that will contain our important CBody component early (complex init tree needs it!)
        _oBodySkinnedMeshGO_HACK.transform.SetParent(_oBodyBase._oBodyRootGO.transform);
        _bEnabled = true;			// Enabled at creation by defnition.

        //bool bForMorphingOnly = false;  //###JUNK (CGame.INSTANCE._GameMode == EGameModes.MorphNew_TEMP);				//####DEV!!!!
        Debug.Log(string.Format("+ Creating body #{0}", _oBodyBase._nBodyID));

        _oObj = new CObject(this, _oBodyBase._nBodyID, typeof(EBodyDef), "Body");
        _oObj.PropGroupBegin("", "", true);
        //_oObj.PropAdd(EBodyDef.Sex,				"Sex",				typeof(EBodySex), (int)EBodySex.Woman,	"");
        //_oObj.PropAdd(EBodyDef.ClothingTop,		"Top Clothing",		typeof(EBodyClothingTop_HACK), 0, "");		//###HACK!!!!
        //_oObj.PropAdd(EBodyDef.ClothingBottom,	"Bottom Clothing",	typeof(EBodyClothingBottom_HACK), 0, "" + CProp.Hide);	//###BROKEN: Need to switch off v****a soft body!!
        //_oObj.PropAdd(EBodyDef.Hair,			"Hair",				typeof(EBodyHair), 0,	"");
        //_oObj.PropAdd(EBodyDef.BtnUpdateBody,	"Update Body",		0,	"", CProp.AsButton);
        _oObj.PropAdd(EBodyDef.BreastSize,		"Breast Size BROKEN",		1.0f, 0.5f, 2.5f, "");		//###BROKEN#11
        _oObj.FinishInitialization();

        //=== Give some reasonable defaults to use when game loads ===		###TODO: Load these from the user's last used body definitions!		####TEMP ####DESIGN: Load from user pref or file?  NOT IN CODE!!
        //		if (_oBodyBase._nBodyID == 0) {
        //			_oObj.PropSet(EBodyDef.Sex,				(int)EBodySex.Woman);
        //			//_oObj.PropSet(EBodyDef.Sex,				(int)EBodySex.Shemale);
        //			_oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp);
        ////			oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.Messy);
        ////			oObj.PropFind(EBodyDef.ClothingTop)._nPropFlags |= CProp.Hide;		//###HACK!!!!
        ////			oObj.PropFind(EBodyDef.BreastSize)._nPropFlags |= -CProp.Hide;
        ////			oObj.PropFind(EBodyDef.Hair)._nPropFlags |= CProp.Hide;
        //		} else {
        //			//_oObj.PropSet(EBodyDef.Sex,				(int)EBodySex.Man);		####REVB
        //			_oObj.PropSet(EBodyDef.Sex,				(int)EBodySex.Shemale);
        //			//oObj.PropSet(EBodyDef.ClothingTop, (int)EBodyClothingTop_HACK.TiedTop);
        //			_oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp);
        //			//if (CGame.INSTANCE._bRunningInEditor)		//###TEMP! :)
        //			//	oObj.PropSet(EBodyDef.BreastSize, 1.3f);
        //		}

        //===== DETACHED SOFTBODY PARTS PROCESSING =====
        if (_oBodyBase._eBodySex != EBodySex.Man) {
            //_aSoftBodies.Add(_oBreastL = (CBreastL)CSoftBody.Create(this, typeof(CBreastL), "chestUpper"));        //###DEVNOW
            //_aSoftBodies.Add(_oBreastR = (CBreastR)CSoftBody.Create(this, typeof(CBreastR), "chestUpper"));
        }
        if (_oBodyBase._eBodySex == EBodySex.Woman) {
            //_aSoftBodies.Add(_oVagina = (CVagina)CSoftBody.Create(this, typeof(CVagina), "chest/abdomen/hip"));
        } else {
            //_aSoftBodies.Add(_oPenis = (CPenis)CSoftBody.Create(this, typeof(CPenis), "chest/abdomen/hip"));
        }

        ////####TEMP ####DESIGN ####TEMP ####MOVE
        //_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "HACK-Cloth-TankTop", "_ClothSkinnedArea_ShoulderTop"));    //_ClothSkinnedArea_Top
        ///_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "BodySuit", "_ClothSkinnedArea_ShoulderTop"));    //_ClothSkinnedArea_Top
        ////_aCloths.Add(CBCloth.Create(this, "Rough1-Holds"));
        ////_aCloths.Add(CBCloth.Create(this, "Rough2-Spreads"));
        ////_aCloths.Add(CBCloth.Create(this, "BodySuit-Top-Trimmed"));
        ////////////###DEV _aCloths.Add(CBCloth.Create(this, "FullShirt"));

        ////=== Create the various soft-body mesh parts that are dependant on the body sex ===
        ////###IMPROVE!!!! Parse array of Blender-pushed softbody into our parts (instead of pulling like below?)
        //if (_bForMorphingOnly == false) {
        //	if (_eBodySex == EBodySex.Woman || _eBodySex == EBodySex.Shemale) {
        //		_aSoftBodies.Add(_oBreastL = (CBreastBase)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Breasts", "Client", "Unity_GetMesh", "'SkinInfo'", typeof(CBreastBase)));           //###WEAK: Create utility function like before???
        //	}
        //	if (_eBodySex == EBodySex.Shemale || _eBodySex == EBodySex.Man)
        //		_aSoftBodies.Add(_oPenis = (CPenis)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Penis", "Client", "Unity_GetMesh", "'NoSkinInfo'", typeof(CPenis)));
        //	if (_eBodySex == EBodySex.Woman)
        //		_oVagina = new CVagina(this);

        //	//=== Create the important body collider that will repel fluid in the scene ===
        //	_oBodyCol = (CBBodyCol)CBBodyCol.Create(null, this, _sNameGameBody);
        //}

        //=== Obtain the source mesh body for normal extraction ===
        ///_oBodySource = CBMesh.Create(null, this, "oMeshSource", typeof(CBMesh));
        ///_oBodySource.GetComponent<MeshRenderer>().enabled = false;					// This mesh is to pull normals only.  Not visible at runtime!

        //===== MAIN SKINNED BODY PROCESSING =====
        //=== Get the main body skinned mesh (has to be done once all softbody parts have been detached) ===
        _oBodySkinnedMesh = (CBSkin)CBMesh.Create(_oBodySkinnedMeshGO_HACK, _oBodyBase, ".oBody.oMeshBody", typeof(CBSkin)); //###IMPROVE#13: Create blender instance string for our CBody?
        _oBodySkinnedMesh.name = "GametimeBody";
        //_oBodySkinnedMesh.GetComponent<SkinnedMeshRenderer>().enabled = false;

        //=== Create a hotspot at the character's head the user can use to invoke our (important) context menu ===
        //###BROKENN
        //      Transform oHeadT = FindBone("chest/neck/head");         // Our hotspot is located on the forehead of the character.
        //_oHotSpot = CHotSpot.CreateHotspot(this, oHeadT, this._sHumanCharacterName, false, new Vector3(0, 0.09f, 0.03f), 2.0f);     //###IMPROVE: Get these offsets from pre-placed nodes on bone structure??

        ////=== Create the head look controller to look at parts of the other body ===
        //###BROKENN
        //      _oHeadLook = _oBodyRootGO.gameObject.AddComponent<CHeadLook>();			//####DESIGN: Keep for morph mode??
        //_oHeadLook.OnStart(this);

        //=== Instantiate the requested hair and pin as child of the head bone ===
        //###BROKENN
        //EBodyHair eBodyHair = (EBodyHair)_oObj.PropGet(EBodyDef.Hair);
        //if (eBodyHair != EBodyHair.None) {
        //	string sNameHair = "HairW-" + eBodyHair.ToString();         //###HACK!!! W extension!		###HACK!!!! Man support!!
        //	GameObject oHairTemplateGO = Resources.Load("Models/Characters/Woman/Hair/" + sNameHair + "/" + sNameHair, typeof(GameObject)) as GameObject;   // Hair has name of folder and filename the same.	//###HACK: Path to hair, selection control, enumeration, etc
        //	_oHairGO = GameObject.Instantiate(oHairTemplateGO) as GameObject;
        //	Transform oBoneHead = FindBone("chest/neck/head");
        //	_oHairGO.transform.parent = oBoneHead;
        //	_oHairGO.transform.localPosition = Vector3.zero;
        //	_oHairGO.transform.localRotation = Quaternion.identity;
        //	if (_eBodySex == EBodySex.Man) {            //###HACK!!!!!! To reuse messy hair for man!!
        //		_oHairGO.transform.localPosition = new Vector3(0, 0.0f, 0.0f);
        //		_oHairGO.transform.localScale = new Vector3(1.07f, 1.07f, 1.08f);
        //	}
        //}

        Body_InitActors();

        ////=== Setup the keys to handle penis control on non-woman bodies ===
        //if (_eBodySex != EBodySex.Woman) {      //###MOVE?        ###OBS ###F
        //	bool bSelectedBodyOnly = (CGame.INSTANCE._nNumPenisInScene_BROKEN > 1);    // Keys below are active if this body is the selected body ONLY if we have more than one man in the scene
        //	if (_oPenis != null) {
        //		_oKeyHook_PenisBaseUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.BaseUpDown), KeyCode.Q, EKeyHookType.QuickMouseEdit, "Penis up/down", 1, bSelectedBodyOnly);
        //		_oKeyHook_PenisShaftUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.ShaftUpDown), KeyCode.E, EKeyHookType.QuickMouseEdit, "Penis bend up/down", 1, bSelectedBodyOnly);
        //		_oKeyHook_PenisDriveStrengthMax = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.DriveStrengthMax), KeyCode.G, EKeyHookType.QuickMouseEdit, "Penis erection", -1, bSelectedBodyOnly);
        //	}
        //}
        _oKeyHook_ChestUpDown = new CKeyHook(_oActor_Chest._oObj.PropFind(EActorChest.Torso_UpDown), KeyCode.T, EKeyHookType.QuickMouseEdit, "Chest forward/back");

        //=== Create the face and its associated morph channels ===
        ///_oFace = (CFace)CBMesh.Create(null, this, "oMeshFace", typeof(CFace));

        //=== Reparent our actor base to the pose root so that user can move / rotate all bodies at once ===
        _oActor_Base.transform.SetParent(CGame.INSTANCE._oPoseRoot.transform);		//###DESIGN#15! Causes problems with regular init/destory of CBody?  Do we really want to keep reparenting for easy full pose movement??>
        _oActor_Base.gameObject.name = _oBodyBase._sBodyPrefix + "_Base";

        //=== Copy references to our actors to our script-friendly CObject variables to provide friendlier access to our scriptable objects ===
        Base    = _oActor_Base._oObj;              // CGamePlay passed us the reference to the right (empty) static object.  We fill it here.
        Chest   = _oActor_Chest._oObj;
        Torso   = _oActor_Torso._oObj;
        Pelvis  = _oActor_Pelvis._oObj;
        ArmL    = _oActor_ArmL._oObj;
        ArmR    = _oActor_ArmR._oObj;
        LegL    = _oActor_LegL._oObj;
        LegR    = _oActor_LegR._oObj;
        Face = null;/// _oFace._oObj;
        ///###BROKEN ###DEVO Penis = (_oPenis == null) ? null : _oPenis._oObjDriver;

        _oScriptPlay = CUtility.FindOrCreateComponent(_oBodyBase._oBodyRootGO.transform, typeof(CScriptPlay)) as CScriptPlay;
        _oScriptPlay.OnStart(this);

        //=== Rotate the 2nd body toward the first and separate slightly loading poses doesn't pile up one on another ===	####MOVE? ####OBS? (Depend on pose?)
        //####PROBLEM: Set separation and don't do in all game modes
        if (_oBodyBase._nBodyID == 0) {
            _oActor_Base.transform.position = new Vector3(0, 0, -CGame.C_BodySeparationAtStart);        //###DESIGN: Don't load base actor instead??  ###BUG Overwrites user setting of base!!!!
        } else {
            _oActor_Base.transform.position = new Vector3(0, 0, CGame.C_BodySeparationAtStart);
            _oActor_Base.transform.rotation = Quaternion.Euler(0, 180, 0);      // Rotate the 2nd body 180 degrees
        }

        ///_oClothEdit_HACK = new CClothEdit(this, "Shirt");

        ///CGame.gBL_SendCmd("CBody", "CBodyBase_GetBodyBase(" + _oBodyBase._nBodyID.ToString() + ").Breasts_ApplyMorph('RESIZE', 'Nipple', 'Center', 'Wide', (1.6, 1.6, 1.6, 0), None)");       //###F ###HACK!!!

        //=== Create the left and right canvases on each side of the body so that panels have a place to be pinned for close-to-body editing ===
        _aUICanvas[0] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Left"));        //###HACK
        _aUICanvas[1] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Right"));        //###DESIGN: Which pin?  Torso or chest?

        //=== Create the Flex collider in Blender and serialize it to Unity ===
        CGame.gBL_SendCmd("CBody", _oBodyBase._sBlenderInstancePath_CBodyBase + ".oBody.CreateFlexCollider(" + CGame.INSTANCE.nDistFlexColliderShrinkMult + ")");
        _oBodyFlexCollider = (CBSkin)CBMesh.Create(null, _oBodyBase, ".oBody.oMeshFlexCollider", typeof(CBSkin));
        _oBodyFlexCollider.name = "FlexCollider";
        _oBodyFlexCollider.transform.SetParent(_oBodySkinnedMesh.transform);		//###IMPROVE#15: Put this common re-parenting and re-naming in Create!
        _oBodyFlexCollider.gameObject.AddComponent<CFlexSkinnedBody>();
        _oBodyFlexCollider.GetComponent<SkinnedMeshRenderer>().enabled = false;     //###IMPROVE: Move into CFlexSkinnedBody??
        _oBodyFlexCollider.UpdateNormals();			//###NOW#15
    }
示例#4
0
 public CMorphChannel(CBodyBase oBodyBase, string sNameMorphChannel)
 {
     _oBodyBase = oBodyBase;
     //=== Get the morphing records from Blender.  Code finds the proper shape key, calculates delta and sends us records that our C++ code processes containing vert and delta vector ===
     _aMorphDataRecords = CByteArray.GetArray_FLOAT("'CBody'", _oBodyBase._sBlenderInstancePath_CBodyBase + ".CMorphChannel_GetMorphVerts('" + sNameMorphChannel + "')");
 }
示例#5
0
文件: CGame.cs 项目: dvochin/Scripts
    public void Start()
    {
        //    StartCoroutine(Coroutine_StartGame());			// Handled by a coroutine so that our 'OnGui' can run to update the 'Please wait' dialog
        //}
        //public IEnumerator Coroutine_StartGame() {		//####OBS: IEnumerator?? //###NOTE: Game is started by iGUICode_Root once it has completely initialized (so as to present the 'Please Wait...' dialog

        Debug.Log("=== CGame.StartGame() ===");
        INSTANCE = this;
        _nTimeAtStart = Time.time;

        //GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CSoftBody));     //###NOW###
        ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CSoftBodyBase));     //###NOW###
        ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CB));     //###NOW###
        ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CFuckOff));
        ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CJointDriver));
        //return;

        _oFlexSolver = FindObjectOfType<uFlex.FlexSolver>();        //###F
        GameObject oSceneGO = GameObject.Find("SCENE/SceneColliders");
        //if (oSceneGO != null)
        //    s_aColliders_Scene = oSceneGO.GetComponentsInChildren<CCollider_OBS>();

        _bRunningInEditor = true;       //###HACK ####REVA Application.isEditor
        _DemoVersion = (_bRunningInEditor == false);		//###CHECK? If dev has Unity code they are non-demo

        _oCursor = CCursor.Cursor_Create();             //###DESIGN!!!!!: REVISIT!	###CLEANUP!!!!!
        Cursor.visible = Application.isEditor;      // _bRunningInEditor;

        //=== Set rapid-access members to text widgets so we can rapidly update them ===
        _oTextUL = GameObject.Find("/UI/CanvasScreen/UL/Text-UL").GetComponent<Text>();
        _oTextUC = GameObject.Find("/UI/CanvasScreen/UC/Text-UC").GetComponent<Text>();
        _oTextUR = GameObject.Find("/UI/CanvasScreen/UR/Text-UR").GetComponent<Text>();

        //=== Create user-adjustable top-level game options ===
        _oObj = new CObject(this, 0, typeof(EGamePlay), "Erotic9");		//###TEMP!!! Main game name in this low-importance GUI???
        _oObj.PropGroupBegin("", "", true);		//###CLEANUP
        //_oObj.PropAdd(EGamePlay.Pleasure,			"Pleasure",		30,		-100,	100,	"Amount of pleasure experienced by game characters.  Influences 'Arousal' (NOTE: Temporary game mechanism)");	//###BUG with first setting
        //_oObj.PropAdd(EGamePlay.Arousal,			"Arousal",		0,		0,		100,	"Current state of arousal from game characters.  Currently influence penis size.  (NOTE: Temporary game mechanism)");
        //_oObj.PropAdd(EGamePlay.PoseRootPos,		"Pose Root Position",typeof(EPoseRootPos), 0,	"Base location of pose root.  (e.g. on bed, by bedside, etc)");
        //_oObj.PropAdd(EGamePlay.PenisSize,			"Penis Size",	0,		0,		100,	"", CProp.ReadOnly | CProp.Hide);
        //_oObj.PropAdd(EGamePlay.PenisErectionMax,	"Erection",		0,		0,		100,	"", CProp.ReadOnly | CProp.Hide);
        //_oObj.PropAdd(EGamePlay.FluidConfig,		"Fluid Configuration", 0, "Display the properties of the Erotic9 fluid simulator.  (Advanced)", CProp.AsButton);
        _oObj.FinishInitialization();
        _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Game Options", false, new Vector3(0, 0.0f, 0.0f), 1.0f);

        //if (_GameModeAtStartup == EGameModes.None) {
        //    yield break;
        //}

        float nDelayForGuiCatchup = _bRunningInEditor ? 0.2f : 0.01f;		//###HACK? ###TUNE: Adjustable delay to give iGUI time to update 'Game is Loading' message, with some extra time inserted to make Unity editor appear more responsive during game awake time
        ///yield return new WaitForSeconds(nDelayForGuiCatchup);

        //=== Send async call to authentication so it is ready by the time game has initialized ===
        //		WWW oWWW = null;
        //		if (Application.genuine) {		//###CHECK: Has any value against piracy???
        //			if (Application.internetReachability != NetworkReachability.NotReachable) {		//###CHECK!!!
        //				//####BROKEN?! Why store it if we don't use it? string sMachineID = PlayerPrefs.GetString(G.C_PlayerPref_MachineID);
        //				string sMachineID = CGame.GetMachineID();		//###CHECK Can cause problems if switching adaptors frequently?
        //				oWWW = new WWW("http://www.erotic9.net/cgi-bin/CheckUser.py?Action=Authenticate&MachineID=" + sMachineID);
        //			} else {
        //				Debug.LogError("Warning: Could not authenticate because of Internet unreacheability.");
        //			}
        //		} else {
        //			Debug.LogError("Warning: Could not authenticate because of executable image corruption.");
        //		}

        //=== Try to load our dll to extract helpful error message if it fails, then release it ===
        //Debug.Log("INIT: Attempting to load ErosEngine.dll");         //###BROKEN!  WTF No longer works loading 64 bit dll??
        //int hLoadLibResult = LoadLibraryEx("ErosEngine.dll", 0, 2);
        //if (hLoadLibResult > 32)
        //	FreeLibrary(hLoadLibResult);			// Free our dll so Unity can load it its way.  Based on code sample at http://support.microsoft.com/kb/142814
        //else
        //	CUtility.ThrowException("ERROR: Failure to load ErosEngine.dll.  Error code = " + hLoadLibResult);		// App unusable.  Study return code to find out what is wrong.
        //Debug.Log("INIT: Succeeded in loading ErosEngine.dll");

        //####OBS? GameObject oGuiGO = GameObject.Find("iGUI");			//###TODO!!! Update game load status... ###IMPROVE: Async load so OnGUI gets called???  (Big hassle for that!)
        Debug.Log("0. Game Awake"); ///yield return new WaitForSeconds(nDelayForGuiCatchup);
        int n123 = ErosEngine.Utility_Test_Return123_HACK();			// Dummy call just to see if DLL will load with Unity
        if (n123 != 123)
            CUtility.ThrowException("ERROR: Failure to get 123 from ErosEngine.dll call to Utility_Test_Return123_HACK.");
        Debug.Log("INIT: Succeeded in loading ErosEngine.dll");

        //=== Initialize our gBlender direct-memory buffers ===
        Debug.Log("1. Shared Memory Creation.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        if (ErosEngine.gBL_Init(CGame.GetFolderPathRuntime()) == false)
            CUtility.ThrowException("ERROR: Could not start gBlender library!  Game unusable.");

        //=== Spawn Blender process ===
        Debug.Log("2. Background Server Start.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);	//###CHECK: Cannot wait long!!
        _hWnd_Unity = (IntPtr)GetActiveWindow();			// Just before we start Blender obtain the HWND of our Unity editor / player window.  We will need this to re-activate our window.  (Starting blender causes it to activate and would require user to alt-tab back to game!!)
        _oProcessBlender = CGame.LaunchProcessBlender("Erotic9.blend");
        if (_oProcessBlender == null)
            CUtility.ThrowException("ERROR: Could not start Blender!  Game unusable.");
        //_nWnd_Blender_HACK = (IntPtr)GetActiveWindow();

        //=== Start Blender (and our gBlender scripts).  Game cannot run without them ===
        Debug.Log("3. Client / Server Handshake.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        if (ErosEngine.gBL_HandshakeBlender() == false)
            CUtility.ThrowException("ERROR: Could not handshake with Blender!  Game unusable.");

        SetForegroundWindow(_hWnd_Unity);           // Set our editor / player back into focus (away from just-spawned Blender)

        //=== Set Blender global variables ===
        CGame.gBL_SendCmd("G", "CGlobals.SetFlexParticleSpacing(" + CGame.INSTANCE.particleSpacing.ToString() + ")");         //###TODO: Add others?

        //=== Start PhysX ===
          //      Debug.Log("4. PhysX3 Init.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        //ErosEngine.PhysX3_Create();						// *Must* occur before any call to physics library...  So make sure this object is listed with high priority in Unity's "Script Execution Order"

        //Debug.Log("5. PhysX2 Init.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        //ErosEngine.PhysX2_Create();						//###IMPROVE!!! Return argument ###NOTROBUST

        //Debug.Log("6. OpenCL Init.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        //		if (System.Environment.CommandLine.Contains("-DisableOpenCL") == false)	//###TODO More / better command line processing?		//###SOON ####BROKEN!!!!! OpenCL breaks cloth GPU!
        //			ErosEngine.MCube_Init();		//###IMPROVE: Log message to user!

        SetForegroundWindow(_hWnd_Unity);			//###WEAK: Can get rid of??

        //=== Start misc stuff ===
        Debug.Log("7. CGame globals.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);
        _oSceneMeshesGO = GameObject.Find("SceneMeshes");			// Remember our scene game object so we can hide/show

        _aGuiMessages = new string[(int)EGameGuiMsg.COUNT];
        _ShowFPS = _ShowSysInfo = _bRunningInEditor;

        //###IMPROVE: Disabled until we need to save CPU cycles...  Create upon user demand to record script!
        //_oScriptRecordUserActions = new CScriptRecord(GetPathScript("RecordedScript"), "Automatically-generated Erotic9 Scene Interation Script");

        _oPoseRoot = GameObject.Find("CPoseRoot").GetComponent<CPoseRoot>();
        _oPoseRoot.OnStart();

        //_oFluid = gameObject.AddComponent<CFluid>();
        //_oFluid.OnAwake();

        Application.targetFrameRate = _TargetFrameRate;			//###BUG!!! Why no effect????
        _DefaultJointSpringOld = _DefaultJointSpring;		//###OBS
        _DefaultJointDampingOld = _DefaultJointDamping;

        _oCamTarget = GameObject.Find("CCamTarget").GetComponent<CCamTarget>();		//###WEAK!!!
        _oCamTarget.OnStart();

        Debug.Log("8. Body Assembly.");  //###???  new WaitForSeconds(nDelayForGuiCatchup);		//###WEAK!!!

        //_oFluid.OnStart();								//###CHECK: Keep interleave

        SetGameModeBasicInteractions(true);

        //=== Find the static scene colliders in 'SceneColliders' node and initialize them ===
        //Debug.Log("CGame.StartGame() Registering Static Colliders: " + s_aColliders_Scene.Length);
          //  if (s_aColliders_Scene != null)
            //foreach (CCollider_OBS oColStatic in s_aColliders_Scene)		// Colliders that are marked as static registered themselves to us in their Awake() so we can start and destroy them
               // oColStatic.OnStart();

        //StartCoroutine(Coroutine_Update100ms());
        StartCoroutine(Coroutine_Update500ms());

        _GameIsRunning = true;
        enabled = true;
        Debug.Log("+++ GameIsRunning ++");

        Debug.Log("7. Scene settling time.");  //###???  new WaitForSeconds(2.0f);		//###DESIGN??  ###TUNE??
        ///_oGui.ShowSceneBlanker(false);
        ///_oGui.ShowPanelGameLoad(false);

        //=== Check result of user authentication ===
        /*
        if (oWWW != null) {
            yield return oWWW;
            string sResultAuth = oWWW.text;
            _DemoVersion = sResultAuth.Contains("Result=OK") == false;		//###IMPROVE: Create parse routine and return server errors
            Debug.Log("Auth Results = " + sResultAuth);
            if (_DemoVersion == false)
                Debug.Log("Starting game in non-demo mode.");
        }*/
        //_DemoVersion = false;
        //if (_DemoVersion)
        //	Debug.Log("Starting game in demo mode.");		//###TODO: Temp caption!

        ///		if (_bRunningInEditor == false)
        ///			CUtility.WndPopup_Create(EWndPopupType.LearnToPlay, null, "Online Help", 50, 50);	// Show the help dialog at start... ###BUG: Does not change the combo box at top!

        SetForegroundWindow(_hWnd_Unity);           //###WEAK: Can get rid of??

        //if (CGame.INSTANCE._GameMode == EGameModes.None)        //####TEMP
        //    return;

        //=== Create the body publicly-editable body definitions that can construct and reconstruct CBody instances ===
        //CGame.INSTANCE._nNumPenisInScene_BROKEN = 0;

        //###NOTE: For simplification in pose files we always have two bodies in the scene with man/shemale being body 0 and woman body 1
        //CreateBody(0);
        //      //CreateBody(1);
        _aBodyBases[0] = new CBodyBase(0, EBodySex.Woman);
        //###BROKEN _aBodyBases[0].SelectBody();

        TemporarilyDisablePhysicsCollision();

        ///SetPenisInVagina(false);		// We initialize the penis in v****a state to false so v****a track colliders don't kick in at scene init

        if (CGame.INSTANCE._GameMode == EGameModes.Play)
            ScenePose_Load("Standing", false);          // Load the default scene pose

        //###TODO ##NOW: Init GUI first!!
        //iGUISmartPrefab_WndPopup.WndPopup_Create(new CObject[] { oObj }, "Game Play", 0, 0);		//###TEMP

        //Time.timeScale = 0.05f;		//###REVA ###TEMP   Gives more time for cloth to settle... but fix it some other way (with far stronger params??)

        ChangeGameMode(_GameModeAtStartup);             // Set the initial game mode as statically requested

        Debug.LogFormat("Time at startup end: {0}", Time.time - _nTimeAtStart);
        //ScenePose_Load("Standing", false);          // Load the default scene pose
    }