Browse Source

Add functions for writing and reading avatar clothing files

This also introduces a filename member in plClothingOutfit so it
can determine whether to read the clothing information from the file
or the vault.
Florian Meißner 11 years ago
parent
commit
3dc6f76b7d
  1. 12
      Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp
  2. 6
      Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp
  3. 108
      Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.cpp
  4. 26
      Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h

12
Sources/Plasma/PubUtilLib/plAvatar/plArmatureMod.cpp

@ -84,6 +84,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plMessage/plListenerMsg.h"
#include "plMessage/plAgeLoadedMsg.h"
#include "plMessage/plParticleUpdateMsg.h"
#include "plMessage/plLoadClothingMsg.h"
#include "plParticleSystem/plParticleSystem.h"
#include "plParticleSystem/plParticleSDLMod.h"
@ -1293,6 +1294,8 @@ bool plArmatureMod::MsgReceive(plMessage* msg)
}
}
// We also want to use the trigger msg when loading an avatar
MsgReceive(avLoadMsg->GetTriggerMsg());
return true;
}
@ -1334,6 +1337,15 @@ bool plArmatureMod::MsgReceive(plMessage* msg)
}
}
plLoadClothingMsg *clothingMsg = plLoadClothingMsg::ConvertNoRef(msg);
if (clothingMsg)
{
// We got a clothing file and are supposed to load our avatar from it.
// Let's tell our outfit to do so!
fClothingOutfit->SetClothingFile(clothingMsg->GetClothingFile());
return true;
}
plLinkEffectBCMsg *linkBCMsg = plLinkEffectBCMsg::ConvertNoRef(msg);
if (linkBCMsg)
{

6
Sources/Plasma/PubUtilLib/plAvatar/plAvBrainHuman.cpp

@ -193,8 +193,10 @@ void plAvBrainHuman::Activate(plArmatureModBase *avMod)
if (fAvMod->GetClothingOutfit() && fAvMod->GetClothingOutfit()->fGroup != plClothingMgr::kClothingBaseNoOptions)
{
if (fAvMod->IsLocalAvatar())
fAvMod->GetClothingOutfit()->ReadFromVault();
if (fAvMod->IsLocalAvatar())
{
fAvMod->GetClothingOutfit()->ReadClothing();
}
else
{
fAvMod->GetClothingOutfit()->WearDefaultClothing();

108
Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.cpp

@ -430,7 +430,8 @@ bool plClothingBase::MsgReceive(plMessage* msg)
/////////////////////////////////////////////////////////////////////////////
plClothingOutfit::plClothingOutfit() :
fTargetLayer(nil), fBase(nil), fGroup(0), fAvatar(nil), fSynchClients(false), fMaterial(nil), fVaultSaveEnabled(true), fMorphsInitDone(false)
fTargetLayer(nullptr), fBase(nullptr), fGroup(0), fAvatar(nullptr), fSynchClients(false), fMaterial(nullptr),
fVaultSaveEnabled(true), fMorphsInitDone(false)
{
fSkinTint.Set(1.f, 0.84, 0.71, 1.f);
fItems.Reset();
@ -802,15 +803,24 @@ void plClothingOutfit::IHandleMorphSDR(plStateDataRecord *sdr)
morph->SetCurrentStateFrom(sdr);
}
void plClothingOutfit::ReadFromVault()
bool plClothingOutfit::ReadClothing()
{
// Have we set a clothing file? If that's the case, load from there.
if (fClothingFile.IsValid())
return IReadFromFile(fClothingFile);
else
return IReadFromVault();
}
bool plClothingOutfit::IReadFromVault()
{
SetupMorphSDL();
WearDefaultClothing();
RelVaultNode * rvn;
if (nil == (rvn = VaultGetAvatarOutfitFolderIncRef()))
return;
RelVaultNode * rvn = VaultGetAvatarOutfitFolderIncRef();
if (!rvn)
return false;
ARRAY(RelVaultNode*) nodes;
rvn->GetChildNodesIncRef(plVault::kNodeType_SDL, 1, &nodes);
@ -844,6 +854,7 @@ void plClothingOutfit::ReadFromVault()
ForceUpdate(true);
rvn->DecRef();
return true;
}
void plClothingOutfit::SaveCustomizations(bool retry /* = true */)
@ -1135,7 +1146,7 @@ void plClothingOutfit::WearMaintainerOutfit()
void plClothingOutfit::RemoveMaintainerOutfit()
{
ReadFromVault();
ReadClothing();
fVaultSaveEnabled = true;
}
@ -1482,6 +1493,91 @@ void plClothingOutfit::SetupMorphSDL()
}
}
bool plClothingOutfit::WriteToFile(const plFileName &filename)
{
if (!filename.IsValid())
return false;
RelVaultNode* rvn = VaultGetAvatarOutfitFolderIncRef();
if (!rvn)
return false;
hsUNIXStream S;
if (!S.Open(filename, "wb")) {
rvn->DecRef();
return false;
}
S.WriteByte(fGroup);
ARRAY(RelVaultNode*) nodes;
rvn->GetChildNodesIncRef(plVault::kNodeType_SDL, 1, &nodes);
S.WriteLE32(nodes.Count());
for (size_t i = 0; i < nodes.Count(); i++) {
VaultSDLNode sdl(nodes[i]);
S.WriteLE32(sdl.GetSDLDataLength());
if (sdl.GetSDLDataLength())
S.Write(sdl.GetSDLDataLength(), sdl.GetSDLData());
nodes[i]->DecRef();
}
rvn->DecRef();
S.Close();
return true;
}
bool plClothingOutfit::IReadFromFile(const plFileName &filename)
{
if (!filename.IsValid())
return false;
hsUNIXStream S;
if (!S.Open(filename))
return false;
bool isLocalAvatar = plAvatarMgr::GetInstance()->GetLocalAvatar()->GetClothingOutfit() == this;
uint8_t gender = S.ReadByte();
if (gender != fGroup) {
if (isLocalAvatar) {
if (gender == plClothingMgr::kClothingBaseMale)
plClothingMgr::ChangeAvatar("Male", filename);
else if (gender == plClothingMgr::kClothingBaseFemale)
plClothingMgr::ChangeAvatar("Female", filename);
}
S.Close();
return true;
}
StripAccessories();
uint32_t nodeCount = S.ReadLE32();
for (size_t i = 0; i < nodeCount; i++) {
uint32_t dataLen = S.ReadLE32();
if (dataLen) {
plString sdlRecName;
int sdlRecVersion;
plStateDataRecord::ReadStreamHeader(&S, &sdlRecName, &sdlRecVersion);
plStateDescriptor* desc = plSDLMgr::GetInstance()->FindDescriptor(sdlRecName, sdlRecVersion);
if (desc) {
plStateDataRecord sdlDataRec(desc);
if (sdlDataRec.Read(&S, 0)) {
if (sdlRecName == kSDLMorphSequence)
IHandleMorphSDR(&sdlDataRec);
else
plClothingSDLModifier::HandleSingleSDR(&sdlDataRec, this);
}
}
}
}
S.Close();
fSynchClients = true;
ForceUpdate(true);
SaveCustomizations(); // Sync with the vault
return true;
}
/////////////////////////////////////////////////////////////////////////////

26
Sources/Plasma/PubUtilLib/plAvatar/plAvatarClothing.h

@ -215,25 +215,49 @@ public:
void IInstanceSharedMeshes(plClothingItem *item);
void IRemoveSharedMeshes(plClothingItem *item);
void ReadFromVault();
/** This will load the avatar clothing. If a clothing file is set,
* we will load from the file, otherwise from the vault.
*/
bool ReadClothing();
void WriteToVault();
void WriteToVault(const ARRAY(plStateDataRecord*) & SDRs);
/** Write the avatar clothing to a file */
bool WriteToFile(const plFileName &filename);
void SetupMorphSDL();
// XXX Don't use this. Temp function for a temp HACK console command.
void DirtyTileset(int tileset);
/** Instruct this plClothingOutfit to read clothing from the given file */
void SetClothingFile(const plFileName &file) { fClothingFile = file; }
/** Returns the clothing file of this outfit. If there is none, an empty string
* will be returned.
*/
plFileName GetClothingFile() const { return fClothingFile; }
protected:
hsBitVector fDirtyItems;
bool fVaultSaveEnabled;
bool fMorphsInitDone;
plFileName fClothingFile;
void IAddItem(plClothingItem *item);
void IRemoveItem(plClothingItem *item);
bool ITintItem(plClothingItem *item, hsColorRGBA color, uint8_t layer);
bool IMorphItem(plClothingItem *item, uint8_t layer, uint8_t delta, float weight);
void IHandleMorphSDR(plStateDataRecord *sdr);
bool IReadFromVault();
/** Read the avatar clothing from a file.
* A local avatar will change the clothing group to the one in the file.
* A local avatar will be invisible if the file does not exist. (used in the Startup age)
*/
bool IReadFromFile(const plFileName &filename);
void IUpdate();

Loading…
Cancel
Save