/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "hsTypes.h" #include "plMaxFileData.h" #include "hsUtils.h" #include "max.h" #include "notify.h" #include "tvnode.h" #define PLASMA_FILE_DATA_CID Class_ID(0x255a700a, 0x285279dc) // MyControl is derived from StdControl, but has no controller functionality. It simply has some // membervariables and saves these by Load and Save. // EditTrackParams and TrackParamsType are responsible for displaying a user interface (RightClick->Properties) // on the controler. With these functions you can avoid it, having an interface ! // As you can see, most of these methods are stubbed. Only Load and Save are implemented // and of course the methods, to access the membervariables. class plMaxFileDataControl : public StdControl { public: SYSTEMTIME fCodeBuildTime; char fBranch[128]; plMaxFileDataControl() { memset(&fCodeBuildTime, 0, sizeof(SYSTEMTIME)); memset(&fBranch, 0, sizeof(fBranch)); } // Animatable virtual void EditTrackParams(TimeValue t, ParamDimensionBase *dim,TCHAR *pname,HWND hParent, IObjParam *ip, DWORD flags){}; int TrackParamsType() { return TRACKPARAMS_WHOLE; } virtual void DeleteThis() { delete this; } // ReferenceMaker virtual RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID,RefMessage message) {return REF_DONTCARE;} Class_ID ClassID() { return PLASMA_FILE_DATA_CID; } SClass_ID SuperClassID() { return CTRL_FLOAT_CLASS_ID; } void GetClassName(TSTR& s) {s = "blah";} // Control methods RefTargetHandle Clone(RemapDir& remap) { return TRACKED_NEW plMaxFileDataControl(); } void Copy(Control *from) {} virtual BOOL IsReplaceable() { return FALSE; } // StdControl methods void GetValueLocalTime(TimeValue t, void *val, Interval &valid, GetSetMethod method=CTRL_ABSOLUTE){} void SetValueLocalTime(TimeValue t, void *val, int commit, GetSetMethod method) {} void Extrapolate(Interval range,TimeValue t,void *val,Interval &valid,int type){} void *CreateTempValue() {return NULL;} void DeleteTempValue(void *val) {} void ApplyValue(void *val, void *delta) {} void MultiplyValue(void *val, float m) {} // MyControl methods IOResult Load(ILoad *iload); IOResult Save(ISave *isave); }; #define MAXFILE_DATA_CHUNK 1001 static const UInt8 kVersion = 1; IOResult plMaxFileDataControl::Load(ILoad *iload) { ULONG nb; IOResult res; while (IO_OK==(res=iload->OpenChunk())) { if (iload->CurChunkID() == MAXFILE_DATA_CHUNK) { UInt8 version = 0; res = iload->Read(&version, sizeof(UInt8), &nb); res = iload->Read(&fCodeBuildTime, sizeof(SYSTEMTIME), &nb); int branchLen = 0; iload->Read(&branchLen, sizeof(int), &nb); iload->Read(&fBranch, branchLen, &nb); } iload->CloseChunk(); if (res != IO_OK) return res; } return IO_OK; } IOResult plMaxFileDataControl::Save(ISave *isave) { ULONG nb; isave->BeginChunk(MAXFILE_DATA_CHUNK); isave->Write(&kVersion, sizeof(kVersion), &nb); isave->Write(&fCodeBuildTime, sizeof(SYSTEMTIME), &nb); int branchLen = strlen(fBranch)+1; isave->Write(&branchLen, sizeof(int), &nb); isave->Write(&fBranch, branchLen, &nb); isave->EndChunk(); return IO_OK; } class MaxFileDataClassDesc : public ClassDesc { public: int IsPublic() { return FALSE; } void* Create(BOOL loading) { return TRACKED_NEW plMaxFileDataControl; } const TCHAR* ClassName() { return _T("MaxFileData"); } SClass_ID SuperClassID() { return CTRL_FLOAT_CLASS_ID; } Class_ID ClassID() { return PLASMA_FILE_DATA_CID; } const TCHAR* Category() { return _T(""); } }; MaxFileDataClassDesc gMaxFileDataClassDesc; ClassDesc *GetMaxFileDataDesc() { return &gMaxFileDataClassDesc; } // This functions searches for Trackviewnode and the Controller and creates one, if none is present. plMaxFileDataControl *GetMaxFileData(bool& created) { plMaxFileDataControl *pCtrl = NULL; ITrackViewNode *tvNode = NULL; ITrackViewNode *tvRoot = GetCOREInterface()->GetTrackViewRootNode(); int i = tvRoot->FindItem(PLASMA_FILE_DATA_CID); if (i < 0) { created = true; tvNode = CreateITrackViewNode(); // This method adds the Node with the specific Title (e.g. "My Settings") tvRoot->AddNode(tvNode, "Plasma Globals", PLASMA_FILE_DATA_CID); pCtrl = (plMaxFileDataControl*)CreateInstance(CTRL_FLOAT_CLASS_ID, PLASMA_FILE_DATA_CID); TSTR s; pCtrl->GetClassName(s); // This adds the controller tvNode->AddController(pCtrl, s, PLASMA_FILE_DATA_CID); tvNode->HideChildren(TRUE); } else { created = false; tvNode = tvRoot->GetNode(i); pCtrl = (plMaxFileDataControl*)tvNode->GetController(PLASMA_FILE_DATA_CID); } return pCtrl; } static SYSTEMTIME gThisCodeBuildTime; static char gThisBranch[128]; static void PrintTime(SYSTEMTIME& time, char* buf) { sprintf(buf, "%d/%d/%d %d:%02d %s", time.wMonth, time.wDay, time.wYear, (time.wHour <= 12) ? time.wHour : time.wHour-12, time.wMinute, (time.wHour < 12 || time.wHour == 24) ? "AM" : "PM"); } static void NotifyProc(void *param, NotifyInfo *info) { if (info->intcode == NOTIFY_FILE_POST_OPEN) { bool created; plMaxFileDataControl* data = GetMaxFileData(created); if (!created) { FILETIME fileTime, pluginTime; SystemTimeToFileTime(&gThisCodeBuildTime, &pluginTime); SystemTimeToFileTime(&data->fCodeBuildTime, &fileTime); if (CompareFileTime(&fileTime, &pluginTime) > 0) { if (hsMessageBox_SuppressPrompts) return; char buf[1024]; strcpy(buf, "This file was last saved with plugins stamped:\n\n"); char timeBuf[128]; PrintTime(data->fCodeBuildTime, timeBuf); strcat(buf, timeBuf); strcat(buf, "\n"); strcat(buf, data->fBranch); strcat(buf, "\n\nThese plugins are stamped:\n\n"); PrintTime(gThisCodeBuildTime, timeBuf); strcat(buf, timeBuf); strcat(buf, "\n"); strcat(buf, gThisBranch); strcat(buf, "\n\nNew features may have been added to the newer plugins,\n" "so saving this file could cause data to be lost."); MessageBox(GetCOREInterface()->GetMAXHWnd(), buf, "Plugin Warning", MB_OK | MB_ICONEXCLAMATION); } } strcpy(data->fBranch, gThisBranch); memcpy(&data->fCodeBuildTime, &gThisCodeBuildTime, sizeof(SYSTEMTIME)); } } static void IGetString(int resID, char *destBuffer, int size) { HRSRC rsrc = ::FindResource(hInstance, MAKEINTRESOURCE(resID), RT_RCDATA); if (rsrc != NULL) { HGLOBAL handle = ::LoadResource(hInstance, rsrc); if (handle != NULL) { char* str = (char*)::LockResource(handle); strncpy(destBuffer, str, size); UnlockResource(handle); } } } void InitMaxFileData() { memset(&gThisCodeBuildTime, 0, sizeof(SYSTEMTIME)); // Date char buf[128]; IGetString(1000, buf, sizeof(buf) - 1); sscanf(buf, "%hu/%hu/%hu", &gThisCodeBuildTime.wMonth, &gThisCodeBuildTime.wDay, &gThisCodeBuildTime.wYear); // Time IGetString(1001, buf, sizeof(buf) - 1); sscanf(buf, "%hu:%hu", &gThisCodeBuildTime.wHour, &gThisCodeBuildTime.wMinute); if (strstr(buf, "PM") != nil) { gThisCodeBuildTime.wHour += 12; } IGetString(1002, gThisBranch, sizeof(gThisBranch) - 1); RegisterNotification(NotifyProc, 0, NOTIFY_FILE_POST_OPEN); }