Descent3/legacy/editor/ScriptMassCompile.cpp
2024-05-24 09:13:36 -04:00

751 lines
18 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* 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 <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/editor/ScriptMassCompile.cpp $
* $Revision: 1.1.1.1 $
* $Date: 2003-08-26 03:57:39 $
* $Author: kevinb $
*
* Implementation of mass script compile dialog
*
* $Log: not supported by cvs2svn $
*
* 9 4/03/99 1:36a Jeff
* added no-check out option for mass compiler
*
* 8 2/25/99 12:34p Jeff
* don't display message if someone has a file checked out during mass
* compile
*
* 7 2/21/99 8:05p Jeff
* better handling of out-of-sync scripts
*
* 6 1/11/99 3:34p Jeff
* added checks for when going editor->game to see if scripts are out of
* date, if so give the option of breaking out. Add some options to mass
* script compiler, along with a toolbar shortcut.
*
* 5 12/30/98 4:39p Jeff
* selectable to what scripts to display (checked out, non-checked out or
* both)
*
* 4 12/20/98 9:57p Jeff
* finished mass compile dialog
*
* 3 12/18/98 12:36p Jeff
* created a function to determine a script's type and hooked it in
*
* 2 12/18/98 12:11p Jeff
* added mass script compile dialog
*
* $NoKeywords: $
*/
// ScriptMassCompile.cpp : implementation file
//
#include "stdafx.h"
#include "editor.h"
#include "ScriptMassCompile.h"
#include "cfile.h"
#include "gamefile.h"
#include "gamefilepage.h"
#include "AppDatabase.h"
#include "Descent.h"
#include "mono.h"
#include "ddio.h"
#include "ScriptCompilerAPI.h"
#include <string.h>
#include <stdarg.h>
#include "mem.h"
#include "pserror.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScriptMassCompile dialog
CString MassScriptEditContent;
CEdit *MassScriptEdit;
void writeline(char *format, ... );
CScriptMassCompile::CScriptMassCompile(CWnd* pParent /*=NULL*/)
: CDialog(CScriptMassCompile::IDD, pParent)
{
//{{AFX_DATA_INIT(CScriptMassCompile)
m_AutoCheckIn = FALSE;
m_DisplayType = 2;
m_NoCheckout = FALSE;
//}}AFX_DATA_INIT
}
void CScriptMassCompile::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CScriptMassCompile)
DDX_Control(pDX, IDC_LIST, m_ScriptList);
DDX_Check(pDX, IDC_AUTOCHECKIN, m_AutoCheckIn);
DDX_Radio(pDX, IDC_LOCKED, m_DisplayType);
DDX_Check(pDX, IDC_NOCHECKOUT, m_NoCheckout);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CScriptMassCompile, CDialog)
//{{AFX_MSG_MAP(CScriptMassCompile)
ON_BN_CLICKED(IDC_BUILD, OnBuild)
ON_BN_CLICKED(IDC_LOCKED, OnLocked)
ON_BN_CLICKED(IDC_NOTLOCKED, OnNotlocked)
ON_BN_CLICKED(IDC_BOTH, OnBoth)
ON_BN_CLICKED(IDC_SELECTALL, OnSelectall)
ON_BN_CLICKED(IDC_OODSCRIPTS, OnOodscripts)
ON_BN_CLICKED(IDC_OOSSCRIPTS, OnOosscripts)
ON_BN_CLICKED(IDC_NOCHECKOUT, OnNocheckout)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScriptMassCompile message handlers
void CScriptMassCompile::OnBuild()
{
UpdateData(true);
MassScriptEditContent = "";
writeline("Starting Mass Build.");
int i,list_size,listbox_size,index;
int *index_map = NULL;
CCheckListBox *list;
char tempbuffer[_MAX_PATH];
CWnd *wnd;
list = (CCheckListBox *)GetDlgItem(IDC_LIST);
listbox_size = list->GetCount();
list_size = 0;
for(i=0;i<listbox_size;i++){
if(list->GetCheck(i)){
list_size++;
}
}
if(list_size==0)
return;
index_map = (int *)mem_malloc(list_size*sizeof(int));
if(!index_map)
return;
index = 0;
for(i=0;i<listbox_size;i++){
if(list->GetCheck(i)){
index_map[index] = i;
index++;
}
}
wnd = (CWnd *)GetDlgItem(IDC_FILENAME);
bool ret1,ret2,ret3,ret4;
for(i=0;i<list_size;i++){
index = index_map[i];
SetStepText(1,"-Not Done-");
SetStepText(2,"-Not Done-");
SetStepText(3,"-Not Done-");
SetStepText(4,"-Not Done-");
list->GetText(index,tempbuffer);
wnd->SetWindowText(tempbuffer);
writeline("------------------------------- %s --------------------------",tempbuffer);
Descent->defer();
ret1 = Step1(tempbuffer);
Descent->defer();
ret2 = Step2(tempbuffer);
Descent->defer();
ret3 = Step3(tempbuffer,ret2);
Descent->defer();
if(ret1){
ret4 = Step4(tempbuffer);
Descent->defer();
}else{
SetStepText(4,"Skipping due to results of Step 1");
writeline("Step 4: Skipped due to result of Step 1 (maybe already checked out)");
ret4 = true;
}
}
OutrageMessageBox("Mass Compile Complete");
mem_free(index_map);
}
void CScriptMassCompile::OnOK()
{
UpdateData(true);
Database->write("EditorScriptAutoCheckin",m_AutoCheckIn);
CDialog::OnOK();
}
void writeline(char *format, ... )
{
char buffer[2048];
va_list marker;
va_start(marker,format);
std::vsprintf(buffer,format,marker);
va_end(marker);
MassScriptEditContent += buffer;
MassScriptEditContent += "\r\n";
MassScriptEdit->SetWindowText(MassScriptEditContent.GetBuffer(0));
Descent->defer();
int total_lines = MassScriptEdit->GetLineCount();
int curr_index = MassScriptEdit->GetFirstVisibleLine();
if( (total_lines-curr_index)>16 ){
//we need to scroll down a line
MassScriptEdit->LineScroll((total_lines-curr_index)-16);
}
}
uint8_t DetermineScriptType(char *filename)
{
CFILE *file;
file = cfopen(filename,"rt");
if(!file){
return 255;
}
char buffer[4096];
bool done = false;
uint8_t script_type = ST_GAME;
cf_ReadString(buffer,4096,file);
while(!(cfeof(file) || done)){
if(strstr(buffer,"GetTriggerScriptID")){
//we found it!
script_type = ST_LEVEL;
done = true;
}
cf_ReadString(buffer,4096,file);
}
cfclose(file);
return script_type;
}
void CScriptMassCompile::BuildList(void)
{
CCheckListBox *list = (CCheckListBox *)GetDlgItem(IDC_LIST);
if(!list)
return;
list->ResetContent();
char buffer[_MAX_PATH];
int length;
for (int i=0;i<MAX_GAMEFILES;i++){
if (Gamefiles[i].used){
//we're only adding .cpp's to this list
length = strlen(Gamefiles[i].name);
if(length>4 && !stricmp(&Gamefiles[i].name[length-4],".cpp")){
switch(m_DisplayType){
case 0: //checked out only
{
if(mng_FindTrackLock(Gamefiles[i].name,PAGETYPE_GAMEFILE)!=-1){
strcpy(buffer,Gamefiles[i].name);
buffer[length-4] = '\0';
list->AddString(buffer);
}
}break;
case 1: //non-check out only
{
if(mng_FindTrackLock(Gamefiles[i].name,PAGETYPE_GAMEFILE)==-1){
strcpy(buffer,Gamefiles[i].name);
buffer[length-4] = '\0';
list->AddString(buffer);
}
}break;
case 2: //both
{
strcpy(buffer,Gamefiles[i].name);
buffer[length-4] = '\0';
list->AddString(buffer);
}break;
};
}
}
}
}
BOOL CScriptMassCompile::OnInitDialog()
{
CDialog::OnInitDialog();
bool bval;
if(Database->read("EditorScriptAutoCheckin",&bval))
m_AutoCheckIn = bval;
else
m_AutoCheckIn = true;
UpdateData(false);
MassScriptEditContent = "";
MassScriptEdit = (CEdit *)GetDlgItem(IDC_OUTPUT);
writeline("System Initialized.");
if(!Network_up){
writeline("WARNING: You did not say yes to the data update, therefore, your work will not be saved for the scripts that you don't currently have checked out.");
}
writeline("------------------------------------------------------------------------------------------------------------------------------------------------");
BuildList();
return TRUE;
}
void CScriptMassCompile::SetStepText(int step,char *format,...)
{
if(step<1 || step>4)
return;
char buffer[1024];
va_list marker;
va_start(marker,format);
std::vsprintf(buffer,format,marker);
va_end(marker);
CWnd *wnd;
int msg_to;
switch(step){
case 1:
wnd = (CWnd *)GetDlgItem(IDC_STEP1);
msg_to = IDC_STEP1;
break;
case 2:
wnd = (CWnd *)GetDlgItem(IDC_STEP2);
msg_to = IDC_STEP2;
break;
case 3:
wnd = (CWnd *)GetDlgItem(IDC_STEP3);
msg_to = IDC_STEP3;
break;
case 4:
wnd = (CWnd *)GetDlgItem(IDC_STEP4);
msg_to = IDC_STEP4;
break;
};
wnd->SetWindowText(buffer);
SendDlgItemMessage( msg_to, WM_PAINT,0,0);
Descent->defer();
}
//return true if the file was checked out for this step
bool CheckOutGamefile(char *tempbuffer,bool show_ok_confirmation,bool report_who_has_locked);
bool CScriptMassCompile::Step1(char *filename)
{
if(!Network_up){
SetStepText(1,"Skipping, Network 'Down'");
writeline("Step 1: Skipping, Due to the NO on data update");
return false;
}
if(m_NoCheckout){
SetStepText(1,"Skipping, 'no checkout' option checked");
writeline("Step 1: Skipping, 'no checkout' option checked");
return false;
}
char source_filename[_MAX_PATH],compiled_filename[_MAX_PATH];
//make the locker
if (!mng_MakeLocker()){
SetStepText(1,"Unable to create locker, can't check out");
writeline("Step 1: Can't make locker file, skipping check out");
return false;
}
//make real filenames
strcpy(source_filename,filename);
strcpy(compiled_filename,filename);
strcat(source_filename,".cpp");
strcat(compiled_filename,".dll");
bool found_script = false,found_compiled = false;
int i;
//make sure the compiled script is in the gamefiles
for(i=0;i<MAX_GAMEFILES;i++){
if(Gamefiles[i].used){
if(!found_script && !stricmp(Gamefiles[i].name,source_filename))
found_script = true;
if(!found_compiled && !stricmp(Gamefiles[i].name,compiled_filename))
found_compiled = true;
}
if(found_script && found_compiled)
break;
}
if(!found_script){
//ummm, this shouldn't happen
MessageBox("Hmmm, I couldn't find the source file for the script in the manage system...this isn't good","Uh oh");
SetStepText(1,"File Not Found");
writeline("Step 1: Couldn't find source script in manage system");
mng_EraseLocker();
return false;
}
bool ntco_script = true,ntco_compiled = true;
if(!found_compiled)
ntco_compiled = false;
//see if we have these checked out
if(mng_FindTrackLock(source_filename,PAGETYPE_GAMEFILE)!=-1)
ntco_script = false;
if(ntco_compiled && mng_FindTrackLock(compiled_filename,PAGETYPE_GAMEFILE)!=-1)
ntco_compiled = false;
//ok, we know what files we need to check out
bool sret = false,cret = false;
if(ntco_script){
writeline("Step 1: Checking out %s",source_filename);
sret = CheckOutGamefile(source_filename,false,false);
if(!sret)
writeline("Step 1: Unable to check out %s",source_filename);
}
if(ntco_compiled){
writeline("Step 1: Checking out %s",compiled_filename);
cret = CheckOutGamefile(compiled_filename,false,false);
if(!cret)
writeline("Step 1: Unable to check out %s",compiled_filename);
}
if( (ntco_script||ntco_compiled) ){
if( ((!ntco_script)||sret) && ((!ntco_compiled)||cret) ){
SetStepText(1,"Files checked out");
writeline("Step 1: Success");
}else{
SetStepText(1,"Error checking files out");
writeline("Step 1: Errors have occurred");
}
}else{
SetStepText(1,"No files needed to be checked out");
writeline("Step 1: Success");
}
mng_EraseLocker();
return (sret||cret);
}
//return true if it's a level script
bool CScriptMassCompile::Step2(char *filename)
{
char source_filename[_MAX_PATH];
strcpy(source_filename,filename);
strcat(source_filename,".cpp");
if(DetermineScriptType(source_filename)==ST_LEVEL){
writeline("Step 2: Determined to be a level script");
SetStepText(2,"Level Script");
return true;
}else{
writeline("Step 2: Determined to be a game script");
SetStepText(2,"Game Script");
return false;
}
return false;
}
void masscompilercallback(char *str)
{
MassScriptEditContent += str;
MassScriptEdit->SetWindowText(MassScriptEditContent.GetBuffer(0));
int total_lines = MassScriptEdit->GetLineCount();
int curr_index = MassScriptEdit->GetFirstVisibleLine();
if( (total_lines-curr_index)>16 ){
//we need to scroll down a line
MassScriptEdit->LineScroll((total_lines-curr_index)-16);
}
Descent->defer();
}
bool CScriptMassCompile::Step3(char *filename,bool islevel)
{
tCompilerInfo ci;
ci.callback = masscompilercallback;
ci.script_type = (islevel)?ST_LEVEL:ST_GAME;
strcpy(ci.source_filename,filename);
strcat(ci.source_filename,".cpp");
char compiled_filename[_MAX_PATH],full_path[_MAX_PATH];
strcpy(compiled_filename,filename);
strcat(compiled_filename,".dll");
ddio_MakePath(full_path,LocalScriptDir,compiled_filename,NULL);
if(cfexist(full_path)){
ddio_DeleteFile (full_path);
}
writeline("===START COMPILE===");
ScriptCompile(&ci);
writeline("");
writeline("===END COMPILE===");
bool ret;
if(cfexist(full_path)){
writeline("Step 3: DLL Created");
SetStepText(3,"DLL Created");
ret = true;
}else{
writeline("Step 3: DLL Not Created");
SetStepText(3,"DLL NOT Created");
ret = false;
}
return ret;
}
bool CheckInGamefile(char *tempbuffer,bool giveok);
bool AddNewGameFile(char *fullpath,char *directory);
bool CScriptMassCompile::Step4(char *filename)
{
if(!Network_up){
SetStepText(4,"Skipping, Network 'Down'");
writeline("Step 4: Skipping, Due to the NO on data update");
return false;
}
if(!m_AutoCheckIn){
SetStepText(4,"Skipping, Auto Checkin box not set");
writeline("Step 4: Skipping, Auto Checkin box not set");
return false;
}
char source_filename[_MAX_PATH],compiled_filename[_MAX_PATH];
//make the locker
if (!mng_MakeLocker()){
SetStepText(4,"Unable to create locker, can't check in");
writeline("Step 4: Can't make locker file, skipping check in");
return false;
}
//make real filenames
strcpy(source_filename,filename);
strcpy(compiled_filename,filename);
strcat(source_filename,".cpp");
strcat(compiled_filename,".dll");
bool ntci_source = false,ntci_compiled = false;
int i;
for(i=0;i<MAX_GAMEFILES;i++){
if(Gamefiles[i].used){
if(!ntci_source && !stricmp(Gamefiles[i].name,source_filename) && (mng_FindTrackLock(source_filename,PAGETYPE_GAMEFILE)!=-1) ){
ntci_source = true;
}
if(!ntci_compiled && !stricmp(Gamefiles[i].name,compiled_filename) && (mng_FindTrackLock(source_filename,PAGETYPE_GAMEFILE)!=-1) ){
ntci_compiled = true;
}
}
if(ntci_source && ntci_compiled)
break;
}
if(!ntci_source && !ntci_compiled){
SetStepText(4,"Skipping, files not checked out");
writeline("Step 4: Skipping because both source and compiled are not checked out or not in the manage system");
mng_EraseLocker();
return false;
}
//check to make sure the compiled version exists
if(!cfexist(compiled_filename)){
writeline("Step 4: %s does not exist...possibly due to compilation errors",compiled_filename);
writeline("Step 4: Aborting check in");
SetStepText(4,"Aborted");
mng_EraseLocker();
return false;
}
//see if we need to add the compiled version to manage system
if(!ntci_compiled){
int j;
for(j=0;j<MAX_GAMEFILES;j++){
if(Gamefiles[j].used){
if(!stricmp(Gamefiles[j].name,compiled_filename))
break;
}
}
if(j>=MAX_GAMEFILES){
//compiled file doesn't exist, we'll need to add it
writeline("Step 4: Attempting to add %s to manage system",compiled_filename);
char fullpath[_MAX_PATH];
ddio_MakePath(fullpath,LocalScriptDir,compiled_filename,NULL);
bool ret = AddNewGameFile(fullpath,"scripts");
if(!ret){
writeline("Step 4: Unable to add %s to manage system",compiled_filename);
writeline("Step 4: Aborting");
SetStepText(4,"Aborted");
mng_EraseLocker();
return false;
}else
ntci_compiled = true;
}
}
//we have at least 1 file to check in
bool sret = true,cret = true;
if(ntci_source){
sret = CheckInGamefile(source_filename,false);
if(!sret){
writeline("Step 4: Unable to check in source file");
}
}
if(ntci_compiled){
cret = CheckInGamefile(compiled_filename,false);
if(!cret){
writeline("Step 4: Unable to check in compiled file");
}
}
if( !sret || !cret ){
SetStepText(4,"There were errors checking in files");
writeline("Step 4: Errors had occurred");
}else{
SetStepText(4,"Success");
writeline("Step 4: Success");
}
mng_EraseLocker();
return (sret||cret);
}
void CScriptMassCompile::OnLocked()
{
UpdateData(true);
BuildList();
}
void CScriptMassCompile::OnNotlocked()
{
UpdateData(true);
BuildList();
}
void CScriptMassCompile::OnBoth()
{
UpdateData(true);
BuildList();
}
void CScriptMassCompile::OnSelectall()
{
CCheckListBox *list = (CCheckListBox *)GetDlgItem(IDC_LIST);
if(!list)
return;
int count = list->GetCount();
for(int i=0;i<count;i++){
list->SetCheck(i,1);
list->SetSel(i,TRUE);
}
}
bool IsScriptOutofDate(char *name);
void CScriptMassCompile::OnOodscripts()
{
CCheckListBox *list = (CCheckListBox *)GetDlgItem(IDC_LIST);
if(!list)
return;
char old_dir[_MAX_PATH];
ddio_GetWorkingDir(old_dir,_MAX_PATH);
ddio_SetWorkingDir(LocalScriptDir);
char filename[_MAX_PATH];
int count = list->GetCount();
for(int i=0;i<count;i++){
list->GetText(i,filename);
strcat(filename,".cpp");
if(IsScriptOutofDate(filename)){
list->SetCheck(i,1);
list->SetSel(i,TRUE);
}else{
list->SetCheck(i,0);
list->SetSel(i,FALSE);
}
}
ddio_SetWorkingDir(old_dir);
}
bool IsScriptOutofSync(char *name);
void CScriptMassCompile::OnOosscripts()
{
CCheckListBox *list = (CCheckListBox *)GetDlgItem(IDC_LIST);
if(!list)
return;
char filename[_MAX_PATH];
int count = list->GetCount();
for(int i=0;i<count;i++){
list->GetText(i,filename);
strcat(filename,".cpp");
if(IsScriptOutofSync(filename)){
list->SetCheck(i,1);
list->SetSel(i,TRUE);
}else{
list->SetCheck(i,0);
list->SetSel(i,FALSE);
}
}
}
void CScriptMassCompile::OnNocheckout()
{
// TODO: Add your control notification handler code here
}