Minimize LEGO1 changes: revert globals, move CreateCharacterClone to extension

Revert plant/building manager globals back to private class statics
(matching master) and use friend declarations for extension access.
Move CreateCharacterClone out of LegoCharacterManager into a new
CharacterCloner class in the multiplayer extension.
This commit is contained in:
Christian Semmler 2026-03-01 10:04:13 -08:00
parent 12a63c105c
commit a0629c45a1
No known key found for this signature in database
GPG Key ID: 086DAA1360BEEE5C
11 changed files with 214 additions and 166 deletions

View File

@ -532,6 +532,7 @@ if (ISLE_EXTENSIONS)
extensions/src/siloader.cpp extensions/src/siloader.cpp
extensions/src/textureloader.cpp extensions/src/textureloader.cpp
extensions/src/multiplayer.cpp extensions/src/multiplayer.cpp
extensions/src/multiplayer/charactercloner.cpp
extensions/src/multiplayer/networkmanager.cpp extensions/src/multiplayer/networkmanager.cpp
extensions/src/multiplayer/remoteplayer.cpp extensions/src/multiplayer/remoteplayer.cpp
extensions/src/multiplayer/websockettransport.cpp extensions/src/multiplayer/websockettransport.cpp

View File

@ -12,6 +12,10 @@ class LegoStorage;
class LegoWorld; class LegoWorld;
class LegoCacheSound; class LegoCacheSound;
class LegoPathBoundary; class LegoPathBoundary;
namespace Multiplayer
{
class NetworkManager;
}
// SIZE 0x2c // SIZE 0x2c
struct LegoBuildingInfo { struct LegoBuildingInfo {
@ -98,7 +102,11 @@ class LegoBuildingManager : public MxCore {
// LegoBuildingManager::`scalar deleting destructor' // LegoBuildingManager::`scalar deleting destructor'
private: private:
friend class Multiplayer::NetworkManager;
static char* g_customizeAnimFile; static char* g_customizeAnimFile;
static MxS32 g_maxMove[16];
static MxU32 g_maxSound;
MxU8 m_nextVariant; // 0x08 MxU8 m_nextVariant; // 0x08
MxBool m_boundariesDetermined; // 0x09 MxBool m_boundariesDetermined; // 0x09

View File

@ -13,6 +13,10 @@ class LegoActor;
class LegoExtraActor; class LegoExtraActor;
class LegoStorage; class LegoStorage;
class LegoROI; class LegoROI;
namespace Multiplayer
{
class CharacterCloner;
}
#pragma warning(disable : 4237) #pragma warning(disable : 4237)
@ -92,13 +96,14 @@ class LegoCharacterManager {
MxU32 GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood); MxU32 GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood);
MxU8 GetMood(LegoROI* p_roi); MxU8 GetMood(LegoROI* p_roi);
LegoROI* CreateAutoROI(const char* p_name, const char* p_lodName, MxBool p_createEntity); LegoROI* CreateAutoROI(const char* p_name, const char* p_lodName, MxBool p_createEntity);
LegoROI* CreateCharacterClone(const char* p_uniqueName, const char* p_characterType);
MxResult UpdateBoundingSphereAndBox(LegoROI* p_roi); MxResult UpdateBoundingSphereAndBox(LegoROI* p_roi);
LegoROI* FUN_10085a80(const char* p_name, const char* p_lodName, MxBool p_createEntity); LegoROI* FUN_10085a80(const char* p_name, const char* p_lodName, MxBool p_createEntity);
static const char* GetCustomizeAnimFile() { return g_customizeAnimFile; } static const char* GetCustomizeAnimFile() { return g_customizeAnimFile; }
private: private:
friend class Multiplayer::CharacterCloner;
LegoROI* CreateActorROI(const char* p_key); LegoROI* CreateActorROI(const char* p_key);
void RemoveROI(LegoROI* p_roi); void RemoveROI(LegoROI* p_roi);
LegoROI* FindChildROI(LegoROI* p_roi, const char* p_name); LegoROI* FindChildROI(LegoROI* p_roi, const char* p_name);

View File

@ -11,6 +11,10 @@ struct LegoPlantInfo;
class LegoROI; class LegoROI;
class LegoStorage; class LegoStorage;
class LegoWorld; class LegoWorld;
namespace Multiplayer
{
class NetworkManager;
}
// VTABLE: LEGO1 0x100d6758 // VTABLE: LEGO1 0x100d6758
// SIZE 0x2c // SIZE 0x2c
@ -67,6 +71,8 @@ class LegoPlantManager : public MxCore {
// LegoPlantManager::`scalar deleting destructor' // LegoPlantManager::`scalar deleting destructor'
private: private:
friend class Multiplayer::NetworkManager;
void RemovePlant(MxS32 p_index, LegoOmni::World p_worldId); void RemovePlant(MxS32 p_index, LegoOmni::World p_worldId);
void AdjustHeight(MxS32 p_index); void AdjustHeight(MxS32 p_index);
LegoPlantInfo* GetInfo(LegoEntity* p_entity); LegoPlantInfo* GetInfo(LegoEntity* p_entity);
@ -74,6 +80,8 @@ class LegoPlantManager : public MxCore {
void AdjustCounter(LegoEntity* p_entity, MxS32 p_adjust); void AdjustCounter(LegoEntity* p_entity, MxS32 p_adjust);
static char* g_customizeAnimFile; static char* g_customizeAnimFile;
static MxS32 g_maxMove[4];
static MxU32 g_maxSound;
LegoOmni::World m_worldId; // 0x08 LegoOmni::World m_worldId; // 0x08
MxBool m_boundariesDetermined; // 0x0c MxBool m_boundariesDetermined; // 0x0c

View File

@ -197,7 +197,7 @@ LegoBuildingInfo g_buildingInfoInit[16] = {
// clang-format on // clang-format on
// GLOBAL: LEGO1 0x100f3738 // GLOBAL: LEGO1 0x100f3738
MxU32 g_buildingMaxSound = 6; MxU32 LegoBuildingManager::g_maxSound = 6;
// GLOBAL: LEGO1 0x100f373c // GLOBAL: LEGO1 0x100f373c
MxU32 g_buildingSoundIdOffset = 0x3c; MxU32 g_buildingSoundIdOffset = 0x3c;
@ -226,7 +226,7 @@ MxS32 g_buildingManagerConfig = 1;
LegoBuildingInfo g_buildingInfo[16]; LegoBuildingInfo g_buildingInfo[16];
// GLOBAL: LEGO1 0x100f3748 // GLOBAL: LEGO1 0x100f3748
MxS32 g_buildingMaxMove[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0}; MxS32 LegoBuildingManager::g_maxMove[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0};
#define HAUS1_INDEX 12 #define HAUS1_INDEX 12
@ -493,7 +493,7 @@ MxBool LegoBuildingManager::SwitchSound(LegoEntity* p_entity)
if (info != NULL && info->m_flags & LegoBuildingInfo::c_hasSounds) { if (info != NULL && info->m_flags & LegoBuildingInfo::c_hasSounds) {
info->m_sound++; info->m_sound++;
if (info->m_sound >= g_buildingMaxSound) { if (info->m_sound >= g_maxSound) {
info->m_sound = 0; info->m_sound = 0;
} }
@ -513,7 +513,7 @@ MxBool LegoBuildingManager::SwitchMove(LegoEntity* p_entity)
if (info != NULL && info->m_flags & LegoBuildingInfo::c_hasMoves) { if (info != NULL && info->m_flags & LegoBuildingInfo::c_hasMoves) {
info->m_move++; info->m_move++;
if (info->m_move >= g_buildingMaxMove[info - g_buildingInfo]) { if (info->m_move >= g_maxMove[info - g_buildingInfo]) {
info->m_move = 0; info->m_move = 0;
} }

View File

@ -1110,146 +1110,3 @@ void CustomizeAnimFileVariable::SetValue(const char* p_value)
BuildingManager()->SetCustomizeAnimFile(p_value); BuildingManager()->SetCustomizeAnimFile(p_value);
} }
} }
// Creates an independent multi-part character ROI clone for multiplayer.
// Same construction logic as CreateActorROI but with a unique name and
// no side effects on g_actorInfo[].m_roi.
LegoROI* LegoCharacterManager::CreateCharacterClone(const char* p_uniqueName, const char* p_characterType)
{
MxBool success = FALSE;
LegoROI* roi = NULL;
BoundingSphere boundingSphere;
BoundingBox boundingBox;
MxMatrix mat;
CompoundObject* comp;
MxS32 i;
Tgl::Renderer* renderer = VideoManager()->GetRenderer();
ViewLODListManager* lodManager = GetViewLODListManager();
LegoTextureContainer* textureContainer = TextureContainer();
LegoActorInfo* info = GetActorInfo(p_characterType);
if (info == NULL) {
goto done;
}
roi = new LegoROI(renderer);
roi->SetName(p_uniqueName);
boundingSphere.Center()[0] = g_actorLODs[c_topLOD].m_boundingSphere[0];
boundingSphere.Center()[1] = g_actorLODs[c_topLOD].m_boundingSphere[1];
boundingSphere.Center()[2] = g_actorLODs[c_topLOD].m_boundingSphere[2];
boundingSphere.Radius() = g_actorLODs[c_topLOD].m_boundingSphere[3];
roi->SetBoundingSphere(boundingSphere);
boundingBox.Min()[0] = g_actorLODs[c_topLOD].m_boundingBox[0];
boundingBox.Min()[1] = g_actorLODs[c_topLOD].m_boundingBox[1];
boundingBox.Min()[2] = g_actorLODs[c_topLOD].m_boundingBox[2];
boundingBox.Max()[0] = g_actorLODs[c_topLOD].m_boundingBox[3];
boundingBox.Max()[1] = g_actorLODs[c_topLOD].m_boundingBox[4];
boundingBox.Max()[2] = g_actorLODs[c_topLOD].m_boundingBox[5];
roi->SetBoundingBox(boundingBox);
comp = new CompoundObject();
roi->SetComp(comp);
for (i = 0; i < sizeOfArray(g_actorLODs) - 1; i++) {
char lodName[256];
LegoActorInfo::Part& part = info->m_parts[i];
const char* parentName;
if (i == 0 || i == 1) {
parentName = part.m_partName[part.m_partNameIndices[part.m_partNameIndex]];
}
else {
parentName = g_actorLODs[i + 1].m_parentName;
}
ViewLODList* lodList = lodManager->Lookup(parentName);
MxS32 lodSize = lodList->Size();
sprintf(lodName, "%s%d", p_uniqueName, i);
ViewLODList* dupLodList = lodManager->Create(lodName, lodSize);
for (MxS32 j = 0; j < lodSize; j++) {
LegoLOD* lod = (LegoLOD*) (*lodList)[j];
LegoLOD* clone = lod->Clone(renderer);
dupLodList->PushBack(clone);
}
lodList->Release();
lodList = dupLodList;
LegoROI* childROI = new LegoROI(renderer, lodList);
lodList->Release();
childROI->SetName(g_actorLODs[i + 1].m_name);
childROI->SetParentROI(roi);
BoundingSphere childBoundingSphere;
childBoundingSphere.Center()[0] = g_actorLODs[i + 1].m_boundingSphere[0];
childBoundingSphere.Center()[1] = g_actorLODs[i + 1].m_boundingSphere[1];
childBoundingSphere.Center()[2] = g_actorLODs[i + 1].m_boundingSphere[2];
childBoundingSphere.Radius() = g_actorLODs[i + 1].m_boundingSphere[3];
childROI->SetBoundingSphere(childBoundingSphere);
BoundingBox childBoundingBox;
childBoundingBox.Min()[0] = g_actorLODs[i + 1].m_boundingBox[0];
childBoundingBox.Min()[1] = g_actorLODs[i + 1].m_boundingBox[1];
childBoundingBox.Min()[2] = g_actorLODs[i + 1].m_boundingBox[2];
childBoundingBox.Max()[0] = g_actorLODs[i + 1].m_boundingBox[3];
childBoundingBox.Max()[1] = g_actorLODs[i + 1].m_boundingBox[4];
childBoundingBox.Max()[2] = g_actorLODs[i + 1].m_boundingBox[5];
childROI->SetBoundingBox(childBoundingBox);
CalcLocalTransform(
Mx3DPointFloat(g_actorLODs[i + 1].m_position),
Mx3DPointFloat(g_actorLODs[i + 1].m_direction),
Mx3DPointFloat(g_actorLODs[i + 1].m_up),
mat
);
childROI->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
if (g_actorLODs[i + 1].m_flags & LegoActorLOD::c_useTexture &&
(i != 0 || part.m_partNameIndices[part.m_partNameIndex] != 0)) {
LegoTextureInfo* textureInfo = textureContainer->Get(part.m_names[part.m_nameIndices[part.m_nameIndex]]);
if (textureInfo != NULL) {
childROI->SetTextureInfo(textureInfo);
childROI->SetLodColor(1.0F, 1.0F, 1.0F, 0.0F);
}
}
else if (g_actorLODs[i + 1].m_flags & LegoActorLOD::c_useColor || (i == 0 && part.m_partNameIndices[part.m_partNameIndex] == 0)) {
LegoFloat red, green, blue, alpha;
childROI->GetRGBAColor(part.m_names[part.m_nameIndices[part.m_nameIndex]], red, green, blue, alpha);
childROI->SetLodColor(red, green, blue, alpha);
}
comp->push_back(childROI);
}
CalcLocalTransform(
Mx3DPointFloat(g_actorLODs[c_topLOD].m_position),
Mx3DPointFloat(g_actorLODs[c_topLOD].m_direction),
Mx3DPointFloat(g_actorLODs[c_topLOD].m_up),
mat
);
roi->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
{
LegoCharacter* character = new LegoCharacter(roi);
char* name = new char[SDL_strlen(p_uniqueName) + 1];
SDL_strlcpy(name, p_uniqueName, SDL_strlen(p_uniqueName) + 1);
(*m_characters)[name] = character;
}
success = TRUE;
done:
if (!success && roi != NULL) {
delete roi;
roi = NULL;
}
return roi;
}

View File

@ -37,7 +37,7 @@ float g_heightPerCount[] = {0.1f, 0.7f, 0.5f, 0.9f};
MxU8 g_counters[] = {1, 2, 2, 3}; MxU8 g_counters[] = {1, 2, 2, 3};
// GLOBAL: LEGO1 0x100f315c // GLOBAL: LEGO1 0x100f315c
MxU32 g_plantMaxSound = 8; MxU32 LegoPlantManager::g_maxSound = 8;
// GLOBAL: LEGO1 0x100f3160 // GLOBAL: LEGO1 0x100f3160
MxU32 g_plantSoundIdOffset = 56; MxU32 g_plantSoundIdOffset = 56;
@ -46,7 +46,7 @@ MxU32 g_plantSoundIdOffset = 56;
MxU32 g_plantSoundIdMoodOffset = 66; MxU32 g_plantSoundIdMoodOffset = 66;
// GLOBAL: LEGO1 0x100f3168 // GLOBAL: LEGO1 0x100f3168
MxS32 g_plantMaxMove[4] = {3, 3, 3, 3}; MxS32 LegoPlantManager::g_maxMove[4] = {3, 3, 3, 3};
// GLOBAL: LEGO1 0x100f3178 // GLOBAL: LEGO1 0x100f3178
MxU32 g_plantAnimationId[4] = {30, 33, 36, 39}; MxU32 g_plantAnimationId[4] = {30, 33, 36, 39};
@ -433,8 +433,8 @@ MxBool LegoPlantManager::SwitchVariant(LegoEntity* p_entity)
lodList->Release(); lodList->Release();
CharacterManager()->UpdateBoundingSphereAndBox(roi); CharacterManager()->UpdateBoundingSphereAndBox(roi);
if (info->m_move != 0 && info->m_move >= g_plantMaxMove[info->m_variant]) { if (info->m_move != 0 && info->m_move >= g_maxMove[info->m_variant]) {
info->m_move = g_plantMaxMove[info->m_variant] - 1; info->m_move = g_maxMove[info->m_variant] - 1;
} }
return TRUE; return TRUE;
@ -450,7 +450,7 @@ MxBool LegoPlantManager::SwitchSound(LegoEntity* p_entity)
if (info != NULL) { if (info != NULL) {
info->m_sound++; info->m_sound++;
if (info->m_sound >= g_plantMaxSound) { if (info->m_sound >= g_maxSound) {
info->m_sound = 0; info->m_sound = 0;
} }
@ -470,7 +470,7 @@ MxBool LegoPlantManager::SwitchMove(LegoEntity* p_entity)
if (info != NULL) { if (info != NULL) {
info->m_move++; info->m_move++;
if (info->m_move >= g_plantMaxMove[info->m_variant]) { if (info->m_move >= g_maxMove[info->m_variant]) {
info->m_move = 0; info->m_move = 0;
} }

View File

@ -0,0 +1,17 @@
#pragma once
class LegoCharacterManager;
class LegoROI;
namespace Multiplayer
{
class CharacterCloner {
public:
// Creates an independent multi-part character ROI clone.
// Same construction logic as CreateActorROI but with a unique name and
// no side effects on g_actorInfo[].m_roi.
static LegoROI* Clone(LegoCharacterManager* p_charMgr, const char* p_uniqueName, const char* p_characterType);
};
} // namespace Multiplayer

View File

@ -0,0 +1,156 @@
#include "extensions/multiplayer/charactercloner.h"
#include "legoactors.h"
#include "legocharactermanager.h"
#include "legovideomanager.h"
#include "misc.h"
#include "misc/legocontainer.h"
#include "realtime/realtime.h"
#include "roi/legolod.h"
#include "roi/legoroi.h"
#include "viewmanager/viewlodlist.h"
#include <SDL3/SDL_stdinc.h>
#include <vec.h>
using namespace Multiplayer;
LegoROI* CharacterCloner::Clone(LegoCharacterManager* p_charMgr, const char* p_uniqueName, const char* p_characterType)
{
MxBool success = FALSE;
LegoROI* roi = NULL;
BoundingSphere boundingSphere;
BoundingBox boundingBox;
MxMatrix mat;
CompoundObject* comp;
MxS32 i;
Tgl::Renderer* renderer = VideoManager()->GetRenderer();
ViewLODListManager* lodManager = GetViewLODListManager();
LegoTextureContainer* textureContainer = TextureContainer();
LegoActorInfo* info = p_charMgr->GetActorInfo(p_characterType);
if (info == NULL) {
goto done;
}
roi = new LegoROI(renderer);
roi->SetName(p_uniqueName);
boundingSphere.Center()[0] = g_actorLODs[c_topLOD].m_boundingSphere[0];
boundingSphere.Center()[1] = g_actorLODs[c_topLOD].m_boundingSphere[1];
boundingSphere.Center()[2] = g_actorLODs[c_topLOD].m_boundingSphere[2];
boundingSphere.Radius() = g_actorLODs[c_topLOD].m_boundingSphere[3];
roi->SetBoundingSphere(boundingSphere);
boundingBox.Min()[0] = g_actorLODs[c_topLOD].m_boundingBox[0];
boundingBox.Min()[1] = g_actorLODs[c_topLOD].m_boundingBox[1];
boundingBox.Min()[2] = g_actorLODs[c_topLOD].m_boundingBox[2];
boundingBox.Max()[0] = g_actorLODs[c_topLOD].m_boundingBox[3];
boundingBox.Max()[1] = g_actorLODs[c_topLOD].m_boundingBox[4];
boundingBox.Max()[2] = g_actorLODs[c_topLOD].m_boundingBox[5];
roi->SetBoundingBox(boundingBox);
comp = new CompoundObject();
roi->SetComp(comp);
for (i = 0; i < sizeOfArray(g_actorLODs) - 1; i++) {
char lodName[256];
LegoActorInfo::Part& part = info->m_parts[i];
const char* parentName;
if (i == 0 || i == 1) {
parentName = part.m_partName[part.m_partNameIndices[part.m_partNameIndex]];
}
else {
parentName = g_actorLODs[i + 1].m_parentName;
}
ViewLODList* lodList = lodManager->Lookup(parentName);
MxS32 lodSize = lodList->Size();
sprintf(lodName, "%s%d", p_uniqueName, i);
ViewLODList* dupLodList = lodManager->Create(lodName, lodSize);
for (MxS32 j = 0; j < lodSize; j++) {
LegoLOD* lod = (LegoLOD*) (*lodList)[j];
LegoLOD* clone = lod->Clone(renderer);
dupLodList->PushBack(clone);
}
lodList->Release();
lodList = dupLodList;
LegoROI* childROI = new LegoROI(renderer, lodList);
lodList->Release();
childROI->SetName(g_actorLODs[i + 1].m_name);
childROI->SetParentROI(roi);
BoundingSphere childBoundingSphere;
childBoundingSphere.Center()[0] = g_actorLODs[i + 1].m_boundingSphere[0];
childBoundingSphere.Center()[1] = g_actorLODs[i + 1].m_boundingSphere[1];
childBoundingSphere.Center()[2] = g_actorLODs[i + 1].m_boundingSphere[2];
childBoundingSphere.Radius() = g_actorLODs[i + 1].m_boundingSphere[3];
childROI->SetBoundingSphere(childBoundingSphere);
BoundingBox childBoundingBox;
childBoundingBox.Min()[0] = g_actorLODs[i + 1].m_boundingBox[0];
childBoundingBox.Min()[1] = g_actorLODs[i + 1].m_boundingBox[1];
childBoundingBox.Min()[2] = g_actorLODs[i + 1].m_boundingBox[2];
childBoundingBox.Max()[0] = g_actorLODs[i + 1].m_boundingBox[3];
childBoundingBox.Max()[1] = g_actorLODs[i + 1].m_boundingBox[4];
childBoundingBox.Max()[2] = g_actorLODs[i + 1].m_boundingBox[5];
childROI->SetBoundingBox(childBoundingBox);
CalcLocalTransform(
Mx3DPointFloat(g_actorLODs[i + 1].m_position),
Mx3DPointFloat(g_actorLODs[i + 1].m_direction),
Mx3DPointFloat(g_actorLODs[i + 1].m_up),
mat
);
childROI->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
if (g_actorLODs[i + 1].m_flags & LegoActorLOD::c_useTexture &&
(i != 0 || part.m_partNameIndices[part.m_partNameIndex] != 0)) {
LegoTextureInfo* textureInfo = textureContainer->Get(part.m_names[part.m_nameIndices[part.m_nameIndex]]);
if (textureInfo != NULL) {
childROI->SetTextureInfo(textureInfo);
childROI->SetLodColor(1.0F, 1.0F, 1.0F, 0.0F);
}
}
else if (g_actorLODs[i + 1].m_flags & LegoActorLOD::c_useColor || (i == 0 && part.m_partNameIndices[part.m_partNameIndex] == 0)) {
LegoFloat red, green, blue, alpha;
childROI->GetRGBAColor(part.m_names[part.m_nameIndices[part.m_nameIndex]], red, green, blue, alpha);
childROI->SetLodColor(red, green, blue, alpha);
}
comp->push_back(childROI);
}
CalcLocalTransform(
Mx3DPointFloat(g_actorLODs[c_topLOD].m_position),
Mx3DPointFloat(g_actorLODs[c_topLOD].m_direction),
Mx3DPointFloat(g_actorLODs[c_topLOD].m_up),
mat
);
roi->WrappedSetLocal2WorldWithWorldDataUpdate(mat);
{
LegoCharacter* character = new LegoCharacter(roi);
char* name = new char[SDL_strlen(p_uniqueName) + 1];
SDL_strlcpy(name, p_uniqueName, SDL_strlen(p_uniqueName) + 1);
(*p_charMgr->m_characters)[name] = character;
}
success = TRUE;
done:
if (!success && roi != NULL) {
delete roi;
roi = NULL;
}
return roi;
}

View File

@ -18,11 +18,7 @@
#include <vector> #include <vector>
extern MxU8 g_counters[]; extern MxU8 g_counters[];
extern MxS32 g_plantMaxMove[];
extern MxU32 g_plantMaxSound;
extern MxU8 g_buildingInfoDownshift[]; extern MxU8 g_buildingInfoDownshift[];
extern MxS32 g_buildingMaxMove[];
extern MxU32 g_buildingMaxSound;
using namespace Multiplayer; using namespace Multiplayer;
@ -676,20 +672,20 @@ void NetworkManager::ApplyWorldEvent(uint8_t p_entityType, uint8_t p_changeType,
} }
// Clamp move to the new variant's max (mirrors SwitchVariant) // Clamp move to the new variant's max (mirrors SwitchVariant)
if (info->m_move != 0 && info->m_move >= (MxU32) g_plantMaxMove[info->m_variant]) { if (info->m_move != 0 && info->m_move >= (MxU32) LegoPlantManager::g_maxMove[info->m_variant]) {
info->m_move = g_plantMaxMove[info->m_variant] - 1; info->m_move = LegoPlantManager::g_maxMove[info->m_variant] - 1;
} }
} }
break; break;
case CHANGE_SOUND: case CHANGE_SOUND:
info->m_sound++; info->m_sound++;
if (info->m_sound >= g_plantMaxSound) { if (info->m_sound >= LegoPlantManager::g_maxSound) {
info->m_sound = 0; info->m_sound = 0;
} }
break; break;
case CHANGE_MOVE: case CHANGE_MOVE:
info->m_move++; info->m_move++;
if (info->m_move >= (MxU32) g_plantMaxMove[info->m_variant]) { if (info->m_move >= (MxU32) LegoPlantManager::g_maxMove[info->m_variant]) {
info->m_move = 0; info->m_move = 0;
} }
break; break;
@ -747,7 +743,7 @@ void NetworkManager::ApplyWorldEvent(uint8_t p_entityType, uint8_t p_changeType,
case CHANGE_SOUND: case CHANGE_SOUND:
if (info->m_flags & LegoBuildingInfo::c_hasSounds) { if (info->m_flags & LegoBuildingInfo::c_hasSounds) {
info->m_sound++; info->m_sound++;
if (info->m_sound >= g_buildingMaxSound) { if (info->m_sound >= LegoBuildingManager::g_maxSound) {
info->m_sound = 0; info->m_sound = 0;
} }
} }
@ -755,7 +751,7 @@ void NetworkManager::ApplyWorldEvent(uint8_t p_entityType, uint8_t p_changeType,
case CHANGE_MOVE: case CHANGE_MOVE:
if (info->m_flags & LegoBuildingInfo::c_hasMoves) { if (info->m_flags & LegoBuildingInfo::c_hasMoves) {
info->m_move++; info->m_move++;
if (info->m_move >= (MxU32) g_buildingMaxMove[p_entityIndex]) { if (info->m_move >= (MxU32) LegoBuildingManager::g_maxMove[p_entityIndex]) {
info->m_move = 0; info->m_move = 0;
} }
} }
@ -788,4 +784,3 @@ void NetworkManager::ApplyWorldEvent(uint8_t p_entityType, uint8_t p_changeType,
} }
} }
} }

View File

@ -2,6 +2,7 @@
#include "3dmanager/lego3dmanager.h" #include "3dmanager/lego3dmanager.h"
#include "anim/legoanim.h" #include "anim/legoanim.h"
#include "extensions/multiplayer/charactercloner.h"
#include "legoactor.h" #include "legoactor.h"
#include "legoanimpresenter.h" #include "legoanimpresenter.h"
#include "legocharactermanager.h" #include "legocharactermanager.h"
@ -79,7 +80,7 @@ void RemotePlayer::Spawn(LegoWorld* p_isleWorld)
return; return;
} }
m_roi = charMgr->CreateCharacterClone(m_uniqueName, actorName); m_roi = CharacterCloner::Clone(charMgr, m_uniqueName, actorName);
if (!m_roi) { if (!m_roi) {
return; return;
} }