Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
348 lines
10 KiB
C++
348 lines
10 KiB
C++
// EditorApplication.cpp: implementation of the EditorApplication class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "MW4GameEd2.h"
|
|
#include "EditorApplication.h"
|
|
#include <MW4\MWTool.hpp>
|
|
#include <MW4\MWPlayer.hpp>
|
|
#include <Buildnum\BuildNum.h>
|
|
#include <Adept\Resource.hpp>
|
|
#include <Adept\DropZone.hpp>
|
|
#include <Adept\Map.hpp>
|
|
#include <Adept\ResourceEffectLibrary.hpp>
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//#############################################################################
|
|
//######################## EditorApplication ######################
|
|
//#############################################################################
|
|
|
|
//#############################################################################
|
|
// Message Support
|
|
//
|
|
const Receiver::MessageEntry
|
|
EditorApplication::MessageEntries[]=
|
|
{
|
|
MESSAGE_ENTRY(EditorApplication, PauseGame)
|
|
};
|
|
|
|
EditorApplication::ClassData*
|
|
EditorApplication::DefaultData = NULL;
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
EditorApplication::InitializeClass()
|
|
{
|
|
Verify(!DefaultData);
|
|
DefaultData =
|
|
new ClassData(
|
|
EditorApplicationClassID,
|
|
"EditorApplication",
|
|
MWApplication::DefaultData,
|
|
ELEMENTS(MessageEntries),
|
|
MessageEntries
|
|
);
|
|
Check_Object(DefaultData);
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
EditorApplication::TerminateClass()
|
|
{
|
|
Check_Object(DefaultData);
|
|
delete DefaultData;
|
|
DefaultData = NULL;
|
|
}
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
EditorApplication*
|
|
EditorApplication::Make()
|
|
{
|
|
return new EditorApplication;
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
EditorApplication::EditorApplication():
|
|
MWApplication(DefaultData,false)
|
|
{
|
|
applicationMode = EditorMode;
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
EditorApplication::~EditorApplication()
|
|
{
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
EditorApplication::LoadGameMessageHandler(int connection, Stuff::MemoryStream *message)
|
|
{
|
|
Check_Object(this);
|
|
MWApplication::LoadGameMessageHandler(connection, message);
|
|
|
|
|
|
//
|
|
//-------------------------------------------------------
|
|
//We need to create a drop zone with the name PlayerStart
|
|
//-------------------------------------------------------
|
|
//
|
|
if(NameTable::GetInstance()->FindID("PlayerStart") == NameTable::NullObjectID)
|
|
{
|
|
Adept::Resource model_resource((LPCSTR)"Content\\Misc\\DropZone\\DropZone.instance");
|
|
Check_Object(&model_resource);
|
|
model_resource.LoadData();
|
|
Verify(model_resource.DoesResourceExist());
|
|
|
|
Adept::Entity *entity;
|
|
Check_Object(Connection::Local);
|
|
ReplicatorID base_id = Connection::Local->GetNextReplicatorID();
|
|
entity = Entity::CreateEntity(&model_resource,&base_id);
|
|
Check_Object(entity);
|
|
|
|
entity->instanceName = "PlayerStart";
|
|
Check_Object(Map::GetInstance());
|
|
Map::GetInstance()->AddChild(entity);
|
|
|
|
entity->SetPropType(Entity::MissionPropType);
|
|
entity->SyncMatrices(true);
|
|
|
|
NameTable::GetInstance()->AddEntry(entity, NameTable::DropZoneArray);
|
|
Verify(NameTable::GetInstance()->IsValid());
|
|
Map::GetInstance()->UpdateZone(entity);
|
|
}
|
|
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//
|
|
void
|
|
EditorApplication::EnterRunningGameState(void* data)
|
|
{
|
|
Check_Object(this);
|
|
MWApplication::EnterRunningGameState(data);
|
|
}
|
|
|
|
void
|
|
EditorApplication::PauseGameMessageHandler(const PauseGameMessage *message)
|
|
{
|
|
Check_Object(this);
|
|
Check_Object(message);
|
|
Verify(message->messageID == PauseGameMessageID);
|
|
}
|
|
|
|
|
|
void
|
|
EditorApplication::LoadMissionResources(const char *mission_name)
|
|
{
|
|
|
|
//
|
|
//---------------------------------------------------------
|
|
// Get the mission instance name and the resource file name
|
|
//---------------------------------------------------------
|
|
//
|
|
Stuff::MString mission_instance = mission_name;
|
|
|
|
// [editor data fix] Derive the mission's compiled resource (.mw4) so BOTH user missions
|
|
// (Resource\UserMissions\<name>.mw4) AND stock missions can be opened. Stock missions
|
|
// compile to Resource\Missions\<short>.mw4 where <short> is an abbreviated, lowercase name
|
|
// declared in the mission's .build (e.g. CentralPark -> cpark.mw4), so it can't be derived
|
|
// by a simple transform. The original code hardcoded "Resource\\User" + (name after first
|
|
// '\\'), which only ever found the few user missions and produced a garbage path (and STOP)
|
|
// for any name lacking a '\\'. Now: extract the bare mission name, prefer the user-mission
|
|
// package, else read the resource path straight out of <name>.build.
|
|
char _bare[256];
|
|
{
|
|
const char* _s = strrchr( (const char*)mission_instance, '\\' );
|
|
_s = _s ? _s + 1 : (const char*)mission_instance;
|
|
Str_Copy( _bare, _s, sizeof(_bare) );
|
|
char* _dot = strrchr( _bare, '.' );
|
|
if( _dot ) *_dot = 0;
|
|
}
|
|
Stuff::MString res_name = "Resource\\UserMissions\\";
|
|
res_name += _bare;
|
|
res_name += ".mw4";
|
|
if( GetFileAttributes( (const char*)res_name ) == 0xFFFFFFFF ) // no user-mission package -> stock mission
|
|
{
|
|
char _bp[512];
|
|
sprintf( _bp, "Content\\Missions\\%s\\%s.build", _bare, _bare );
|
|
FILE* _bf = fopen( _bp, "r" );
|
|
if( _bf )
|
|
{
|
|
char _ln[512];
|
|
while( fgets( _ln, sizeof(_ln), _bf ) )
|
|
{
|
|
char* _lb = strchr( _ln, '[' );
|
|
char* _rb = _lb ? strchr( _lb, ']' ) : 0;
|
|
if( _lb && _rb && _rb > _lb && strstr( _lb, ".mw4" ) )
|
|
{
|
|
*_rb = 0;
|
|
res_name = _lb + 1; // e.g. resource\missions\cpark.mw4
|
|
break;
|
|
}
|
|
}
|
|
fclose( _bf );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Since databases override the file hooking I have to specifically
|
|
// make sure we do or don't need to translate the name at this point.
|
|
//
|
|
TranslateMissionNameIfNecessary(res_name);
|
|
//
|
|
//-------------------------------------------------------------------
|
|
// Open up the resource file as a database and access record 0. This
|
|
// will contain the list of resource files this one is dependant on
|
|
//-------------------------------------------------------------------
|
|
//
|
|
|
|
Stuff::DatabaseHandle *database =
|
|
new Stuff::DatabaseHandle(res_name, false, VER_CONTENTVERSION);
|
|
Stuff::RecordHandle record;
|
|
record.m_databaseHandle = database;
|
|
record.m_ID = ResourceID::BuildDependenciesRecordID;
|
|
#if defined(_ARMOR)
|
|
bool result =
|
|
#endif
|
|
record.FindID(true);
|
|
Verify(result);
|
|
|
|
//
|
|
//-------------------------
|
|
// Load up the core effects
|
|
//-------------------------
|
|
//
|
|
Verify(!gosFX::EffectLibrary::Instance);
|
|
gosFX::EffectLibrary::Instance = new ResourceEffectLibrary;
|
|
Resource core_libraries("{effects}");
|
|
Verify(core_libraries.DoesResourceExist());
|
|
core_libraries.LoadData();
|
|
ResourceID *lib = Cast_Pointer(ResourceID*, core_libraries.GetPointer());
|
|
for (unsigned i=0; i<core_libraries.GetSize()/sizeof(ResourceID); ++i, ++lib)
|
|
{
|
|
Resource library(*lib);
|
|
gosFX::EffectLibrary::Instance->Load(&library);
|
|
}
|
|
|
|
//
|
|
//----------------------------------------------------------------------
|
|
// The data points to a series of null terminated strings. Step through
|
|
// them until done
|
|
//----------------------------------------------------------------------
|
|
//
|
|
const char* data = reinterpret_cast<const char*>(record.m_data);
|
|
short level=MapResourceFileID;
|
|
for (DWORD count=0; count<record.m_length; ++level)
|
|
{
|
|
if (!data[count])
|
|
break;
|
|
|
|
// MString depstr=data+count;
|
|
// strcpy(strrchr(depstr,'.')+1,"dep");
|
|
//
|
|
//---------------------------
|
|
// Load this resource file up
|
|
//---------------------------
|
|
//
|
|
ResourceManager::Instance->OpenResourceFile(
|
|
data+count,
|
|
NULL,
|
|
level,
|
|
VER_CONTENTVERSION,
|
|
false,
|
|
false
|
|
);
|
|
|
|
//
|
|
//----------------------------
|
|
// Load up this file's effects
|
|
//----------------------------
|
|
//
|
|
Resource libraries("{effects}");
|
|
libraries.LoadData();
|
|
if (libraries.DoesResourceExist() && libraries.GetResourceID().GetFileID() == level)
|
|
{
|
|
ResourceID *lib = Cast_Pointer(ResourceID*, libraries.GetPointer());
|
|
for (unsigned i=0; i<libraries.GetSize()/sizeof(ResourceID); ++i, ++lib)
|
|
{
|
|
Resource library(*lib);
|
|
gosFX::EffectLibrary::Instance->Load(&library);
|
|
}
|
|
}
|
|
count += strlen(data+count)+1;
|
|
}
|
|
//
|
|
//---------------------------------
|
|
// Now create our own resource file
|
|
//---------------------------------
|
|
//
|
|
// MString depstr=res_name;
|
|
// strcpy(strrchr(depstr,'.')+1,"dep");
|
|
|
|
ResourceManager::Instance->OpenResourceFile(database,
|
|
level,
|
|
false);
|
|
Resource libraries("{effects}");
|
|
libraries.LoadData();
|
|
if (libraries.DoesResourceExist() && libraries.GetResourceID().GetFileID() == level)
|
|
{
|
|
ResourceID *lib = Cast_Pointer(ResourceID*, libraries.GetPointer());
|
|
for (unsigned i=0; i<libraries.GetSize()/sizeof(ResourceID); ++i, ++lib)
|
|
{
|
|
Resource library(*lib);
|
|
gosFX::EffectLibrary::Instance->Load(&library);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Entity::CreateMessage *
|
|
EditorApplication::MakePlayerCreationMessage(int player_id)
|
|
{
|
|
|
|
Resource vehicle_instance("Content\\Vehicles\\ObservationVehicle\\ObservationVehicle.instance");
|
|
vehicle_instance.LoadData();
|
|
MString interface_name = "Interfaces\\SimpleInterface\\SimpleInterface.instance";
|
|
Resource interface_instance(interface_name);
|
|
interface_instance.LoadData();
|
|
Resource player_data("Players\\TestPlayer\\TestPlayer.data");
|
|
player_data.LoadData();
|
|
|
|
MWPlayer::CreateMessage *player_message =
|
|
new MWPlayer::CreateMessage(
|
|
sizeof(MWPlayer::CreateMessage),
|
|
DefaultEventPriority,
|
|
MWPlayer::CreateMessage::DefaultFlags,
|
|
MWPlayerClassID,
|
|
0,
|
|
player_data.GetResourceID(),
|
|
LinearMatrix4D::Identity,
|
|
0.0f,
|
|
MWPlayer::ExecutionStateEngine::AlwaysExecuteState,
|
|
NameTableEntry::BuildObjectID(NameTable::PlayerArray, 0),
|
|
Entity::Player,
|
|
vehicle_instance.GetResourceID(),
|
|
interface_instance.GetResourceID(),
|
|
NameTable::NullObjectID,
|
|
0,
|
|
DefaultSkinPrefix,
|
|
0,
|
|
0
|
|
);
|
|
Check_Object(player_message);
|
|
|
|
return player_message;
|
|
|
|
}
|
|
|