From f4243cffeb6f889bf4d4be7a4f93728c225c9a5e Mon Sep 17 00:00:00 2001 From: Anonymous Date: Tue, 14 Jan 2014 09:22:49 -0700 Subject: [PATCH] Added the sharedObject library --- engine/shared/library/CMakeLists.txt | 1 + .../src/shared/DataResourceList.h | 4 +- .../library/sharedObject/CMakeLists.txt | 12 + .../CustomizationData_Directory.h | 1 + .../CustomizationData_LocalDirectory.h | 1 + .../CustomizationData_RemoteDirectory.h | 1 + .../include/public/sharedObject/AlterResult.h | 1 + .../public/sharedObject/AlterScheduler.h | 1 + .../include/public/sharedObject/Appearance.h | 1 + .../public/sharedObject/AppearanceTemplate.h | 1 + .../sharedObject/AppearanceTemplateList.h | 1 + .../sharedObject/ArrangementDescriptor.h | 1 + .../sharedObject/ArrangementDescriptorList.h | 1 + .../BasicRangedIntCustomizationVariable.h | 1 + .../public/sharedObject/CachedNetworkId.h | 1 + .../sharedObject/CachedNetworkIdArchive.h | 1 + .../public/sharedObject/CellProperty.h | 1 + .../public/sharedObject/ConfigSharedObject.h | 1 + .../public/sharedObject/ContainedByProperty.h | 1 + .../include/public/sharedObject/Container.h | 1 + .../include/public/sharedObject/Controller.h | 1 + .../public/sharedObject/CustomizationData.h | 1 + .../sharedObject/CustomizationDataProperty.h | 1 + .../sharedObject/CustomizationIdManager.h | 1 + .../sharedObject/CustomizationVariable.h | 1 + .../public/sharedObject/DebugNotification.h | 1 + .../DebugYawedFloorNotification.h | 1 + .../include/public/sharedObject/Dynamics.h | 1 + .../public/sharedObject/FirstSharedObject.h | 1 + .../include/public/sharedObject/Hardpoint.h | 1 + .../public/sharedObject/LayerProperty.h | 1 + .../include/public/sharedObject/LotManager.h | 1 + .../include/public/sharedObject/LotType.h | 1 + .../sharedObject/MemoryBlockManagedObject.h | 1 + .../public/sharedObject/MovementTable.h | 1 + .../public/sharedObject/NetworkController.h | 1 + .../public/sharedObject/NetworkIdManager.h | 1 + .../public/sharedObject/NoRenderAppearance.h | 1 + .../sharedObject/NoRenderAppearanceTemplate.h | 1 + .../include/public/sharedObject/Object.h | 1 + .../include/public/sharedObject/ObjectList.h | 1 + .../public/sharedObject/ObjectNotification.h | 1 + .../public/sharedObject/ObjectSetMessage.def | 1 + .../public/sharedObject/ObjectSetMessage.h | 1 + .../public/sharedObject/ObjectTemplate.h | 1 + .../ObjectTemplateCustomizationDataWriter.h | 1 + .../public/sharedObject/ObjectTemplateList.h | 1 + .../public/sharedObject/ObjectWatcherList.h | 1 + .../PaletteColorCustomizationVariable.h | 1 + .../include/public/sharedObject/Portal.h | 1 + .../public/sharedObject/PortalProperty.h | 1 + .../sharedObject/PortalPropertyTemplate.h | 1 + .../sharedObject/PortalPropertyTemplateList.h | 1 + .../sharedObject/PortallizedSphereTree.h | 2 + .../include/public/sharedObject/Property.h | 1 + .../include/public/sharedObject/PropertyId.h | 1 + .../public/sharedObject/PulseDynamics.h | 1 + .../RangedIntCustomizationVariable.h | 1 + .../public/sharedObject/RotationDynamics.h | 1 + .../public/sharedObject/ScheduleData.h | 1 + .../public/sharedObject/SeesawDynamics.h | 1 + .../public/sharedObject/SetupSharedObject.h | 1 + .../public/sharedObject/SimpleDynamics.h | 1 + .../public/sharedObject/SlotDescriptor.h | 1 + .../public/sharedObject/SlotDescriptorList.h | 1 + .../include/public/sharedObject/SlotId.h | 1 + .../public/sharedObject/SlotIdArchive.h | 1 + .../public/sharedObject/SlotIdManager.h | 1 + .../include/public/sharedObject/SlotType.def | 1 + .../public/sharedObject/SlottedContainer.h | 1 + .../sharedObject/SlottedContainmentProperty.h | 1 + .../include/public/sharedObject/SphereGrid.h | 2 + .../public/sharedObject/SpringDynamics.h | 1 + .../public/sharedObject/StateDynamics.h | 1 + .../public/sharedObject/StructureFootprint.h | 1 + .../public/sharedObject/TextAppearance.h | 1 + .../public/sharedObject/TrackingDynamics.h | 1 + .../include/public/sharedObject/Tweakable.h | 1 + .../public/sharedObject/VolumeContainer.h | 1 + .../sharedObject/VolumeContainmentProperty.h | 1 + .../include/public/sharedObject/World.h | 1 + .../library/sharedObject/src/CMakeLists.txt | 196 + .../src/shared/ObjectWatcherList.cpp | 457 +++ .../src/shared/ObjectWatcherList.h | 76 + .../src/shared/appearance/Appearance.cpp | 896 +++++ .../src/shared/appearance/Appearance.h | 273 ++ .../shared/appearance/AppearanceTemplate.cpp | 494 +++ .../shared/appearance/AppearanceTemplate.h | 153 + .../appearance/AppearanceTemplateList.cpp | 736 ++++ .../appearance/AppearanceTemplateList.h | 62 + .../src/shared/appearance/Hardpoint.cpp | 34 + .../src/shared/appearance/Hardpoint.h | 91 + .../shared/appearance/NoRenderAppearance.cpp | 21 + .../shared/appearance/NoRenderAppearance.h | 38 + .../appearance/NoRenderAppearanceTemplate.cpp | 64 + .../appearance/NoRenderAppearanceTemplate.h | 40 + .../src/shared/appearance/TextAppearance.cpp | 25 + .../src/shared/appearance/TextAppearance.h | 38 + .../src/shared/appearance/Tweakable.cpp | 36 + .../src/shared/appearance/Tweakable.h | 40 + .../container/ArrangementDescriptor.cpp | 154 + .../shared/container/ArrangementDescriptor.h | 66 + .../container/ArrangementDescriptorList.cpp | 156 + .../container/ArrangementDescriptorList.h | 52 + .../shared/container/ContainedByProperty.cpp | 81 + .../shared/container/ContainedByProperty.h | 48 + .../src/shared/container/Container.cpp | 856 +++++ .../src/shared/container/Container.h | 199 + .../src/shared/container/SlotDescriptor.cpp | 134 + .../src/shared/container/SlotDescriptor.h | 74 + .../shared/container/SlotDescriptorList.cpp | 153 + .../src/shared/container/SlotDescriptorList.h | 58 + .../src/shared/container/SlotId.cpp | 46 + .../src/shared/container/SlotId.h | 77 + .../src/shared/container/SlotIdArchive.h | 41 + .../src/shared/container/SlotIdManager.cpp | 565 +++ .../src/shared/container/SlotIdManager.h | 61 + .../src/shared/container/SlotType.def | 6 + .../src/shared/container/SlottedContainer.cpp | 875 +++++ .../src/shared/container/SlottedContainer.h | 92 + .../container/SlottedContainmentProperty.cpp | 243 ++ .../container/SlottedContainmentProperty.h | 73 + .../src/shared/container/VolumeContainer.cpp | 480 +++ .../src/shared/container/VolumeContainer.h | 98 + .../container/VolumeContainmentProperty.cpp | 62 + .../container/VolumeContainmentProperty.h | 48 + .../src/shared/controller/Controller.cpp | 267 ++ .../src/shared/controller/Controller.h | 114 + .../shared/controller/NetworkController.cpp | 139 + .../src/shared/controller/NetworkController.h | 58 + .../shared/controller/ObjectSetMessage.def | 83 + .../src/shared/controller/ObjectSetMessage.h | 42 + .../src/shared/controller/printCmValues.pl | 10 + .../src/shared/core/ConfigSharedObject.cpp | 168 + .../src/shared/core/ConfigSharedObject.h | 47 + .../src/shared/core/FirstSharedObject.h | 18 + .../src/shared/core/SetupSharedObject.cpp | 195 + .../src/shared/core/SetupSharedObject.h | 100 + .../BasicRangedIntCustomizationVariable.cpp | 97 + .../BasicRangedIntCustomizationVariable.h | 57 + .../customization/CustomizationData.cpp | 1326 +++++++ .../shared/customization/CustomizationData.h | 214 ++ .../CustomizationData_Directory.h | 92 + .../CustomizationData_LocalDirectory.cpp | 625 +++ .../CustomizationData_LocalDirectory.h | 83 + .../CustomizationData_RemoteDirectory.cpp | 194 + .../CustomizationData_RemoteDirectory.h | 72 + .../customization/CustomizationIdManager.cpp | 222 ++ .../customization/CustomizationIdManager.h | 28 + .../customization/CustomizationVariable.cpp | 49 + .../customization/CustomizationVariable.h | 106 + .../ObjectTemplateCustomizationDataWriter.cpp | 228 ++ .../ObjectTemplateCustomizationDataWriter.h | 58 + .../PaletteColorCustomizationVariable.cpp | 146 + .../PaletteColorCustomizationVariable.h | 64 + .../RangedIntCustomizationVariable.cpp | 285 ++ .../RangedIntCustomizationVariable.h | 63 + .../src/shared/dynamics/Dynamics.cpp | 56 + .../src/shared/dynamics/Dynamics.h | 69 + .../src/shared/dynamics/PulseDynamics.cpp | 61 + .../src/shared/dynamics/PulseDynamics.h | 42 + .../src/shared/dynamics/RotationDynamics.cpp | 71 + .../src/shared/dynamics/RotationDynamics.h | 47 + .../src/shared/dynamics/SeesawDynamics.cpp | 61 + .../src/shared/dynamics/SeesawDynamics.h | 56 + .../src/shared/dynamics/SimpleDynamics.cpp | 110 + .../src/shared/dynamics/SimpleDynamics.h | 58 + .../src/shared/dynamics/SpringDynamics.cpp | 69 + .../src/shared/dynamics/SpringDynamics.h | 53 + .../src/shared/dynamics/StateDynamics.cpp | 106 + .../src/shared/dynamics/StateDynamics.h | 59 + .../src/shared/dynamics/TrackingDynamics.cpp | 91 + .../src/shared/dynamics/TrackingDynamics.h | 53 + .../src/shared/lot/LotManager.cpp | 536 +++ .../sharedObject/src/shared/lot/LotManager.h | 138 + .../sharedObject/src/shared/lot/LotType.h | 35 + .../src/shared/lot/StructureFootprint.cpp | 306 ++ .../src/shared/lot/StructureFootprint.h | 73 + .../src/shared/movement/MovementTable.cpp | 493 +++ .../src/shared/movement/MovementTable.h | 87 + .../src/shared/object/AlterResult.cpp | 53 + .../src/shared/object/AlterResult.h | 145 + .../src/shared/object/AlterScheduler.cpp | 1435 +++++++ .../src/shared/object/AlterScheduler.h | 112 + .../src/shared/object/CachedNetworkId.cpp | 184 + .../src/shared/object/CachedNetworkId.h | 78 + .../shared/object/CachedNetworkIdArchive.h | 33 + .../src/shared/object/DebugNotification.cpp | 86 + .../src/shared/object/DebugNotification.h | 52 + .../object/DebugYawedFloorNotification.cpp | 87 + .../object/DebugYawedFloorNotification.h | 46 + .../object/MemoryBlockManagedObject.cpp | 26 + .../shared/object/MemoryBlockManagedObject.h | 52 + .../src/shared/object/NetworkIdManager.cpp | 103 + .../src/shared/object/NetworkIdManager.h | 48 + .../sharedObject/src/shared/object/Object.cpp | 3388 +++++++++++++++++ .../sharedObject/src/shared/object/Object.h | 1367 +++++++ .../src/shared/object/ObjectList.cpp | 425 +++ .../src/shared/object/ObjectList.h | 73 + .../src/shared/object/ObjectNotification.cpp | 117 + .../src/shared/object/ObjectNotification.h | 62 + .../src/shared/object/ObjectTemplate.cpp | 263 ++ .../src/shared/object/ObjectTemplate.h | 94 + .../src/shared/object/ObjectTemplateList.cpp | 202 + .../src/shared/object/ObjectTemplateList.h | 79 + .../src/shared/object/ScheduleData.cpp | 50 + .../src/shared/object/ScheduleData.h | 203 + .../src/shared/portal/CellProperty.cpp | 1303 +++++++ .../src/shared/portal/CellProperty.h | 295 ++ .../sharedObject/src/shared/portal/Portal.cpp | 429 +++ .../sharedObject/src/shared/portal/Portal.h | 149 + .../src/shared/portal/PortalProperty.cpp | 716 ++++ .../src/shared/portal/PortalProperty.h | 133 + .../shared/portal/PortalPropertyTemplate.cpp | 1774 +++++++++ .../shared/portal/PortalPropertyTemplate.h | 294 ++ .../portal/PortalPropertyTemplateList.cpp | 81 + .../portal/PortalPropertyTemplateList.h | 35 + .../src/shared/portal/PortallizedSphereTree.h | 480 +++ .../src/shared/portal/SphereGrid.h | 559 +++ .../property/CustomizationDataProperty.cpp | 83 + .../property/CustomizationDataProperty.h | 50 + .../src/shared/property/LayerProperty.cpp | 51 + .../src/shared/property/LayerProperty.h | 54 + .../src/shared/property/Property.cpp | 52 + .../src/shared/property/Property.h | 80 + .../src/shared/property/PropertyId.h | 19 + .../sharedObject/src/shared/world/World.cpp | 578 +++ .../sharedObject/src/shared/world/World.h | 135 + .../src/win32/FirstSharedObject.cpp | 8 + 229 files changed, 32864 insertions(+), 2 deletions(-) create mode 100644 engine/shared/library/sharedObject/CMakeLists.txt create mode 100644 engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_Directory.h create mode 100644 engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_LocalDirectory.h create mode 100644 engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_RemoteDirectory.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/AlterResult.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/AlterScheduler.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Appearance.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplate.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplateList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptor.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptorList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/BasicRangedIntCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkId.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkIdArchive.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CellProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ConfigSharedObject.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ContainedByProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Container.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Controller.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CustomizationData.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CustomizationDataProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CustomizationIdManager.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/CustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/DebugNotification.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/DebugYawedFloorNotification.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Dynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/FirstSharedObject.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Hardpoint.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/LayerProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/LotManager.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/LotType.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/MemoryBlockManagedObject.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/MovementTable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/NetworkController.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/NetworkIdManager.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearance.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearanceTemplate.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Object.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectNotification.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.def create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplate.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateCustomizationDataWriter.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ObjectWatcherList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PaletteColorCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Portal.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PortalProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplate.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplateList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PortallizedSphereTree.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Property.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PropertyId.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/PulseDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/RangedIntCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/RotationDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/ScheduleData.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SeesawDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SetupSharedObject.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SimpleDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptor.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptorList.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotId.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotIdArchive.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotIdManager.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlotType.def create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainer.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainmentProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SphereGrid.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/SpringDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/StateDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/StructureFootprint.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/TextAppearance.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/TrackingDynamics.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/Tweakable.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainer.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainmentProperty.h create mode 100644 engine/shared/library/sharedObject/include/public/sharedObject/World.h create mode 100644 engine/shared/library/sharedObject/src/CMakeLists.txt create mode 100644 engine/shared/library/sharedObject/src/shared/ObjectWatcherList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/ObjectWatcherList.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Appearance.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Appearance.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.h create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Tweakable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/appearance/Tweakable.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/Container.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/Container.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotId.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotId.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotIdArchive.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotIdManager.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotIdManager.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlotType.def create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlottedContainer.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlottedContainer.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/VolumeContainer.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/VolumeContainer.h create mode 100644 engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/controller/Controller.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/controller/Controller.h create mode 100644 engine/shared/library/sharedObject/src/shared/controller/NetworkController.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/controller/NetworkController.h create mode 100644 engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.def create mode 100644 engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.h create mode 100644 engine/shared/library/sharedObject/src/shared/controller/printCmValues.pl create mode 100644 engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.h create mode 100644 engine/shared/library/sharedObject/src/shared/core/FirstSharedObject.h create mode 100644 engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData_Directory.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.h create mode 100644 engine/shared/library/sharedObject/src/shared/lot/LotManager.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/lot/LotManager.h create mode 100644 engine/shared/library/sharedObject/src/shared/lot/LotType.h create mode 100644 engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.h create mode 100644 engine/shared/library/sharedObject/src/shared/movement/MovementTable.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/movement/MovementTable.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/AlterResult.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/AlterResult.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/AlterScheduler.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/CachedNetworkIdArchive.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/DebugNotification.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/DebugNotification.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/Object.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/Object.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectList.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectNotification.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectNotification.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.h create mode 100644 engine/shared/library/sharedObject/src/shared/object/ScheduleData.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/object/ScheduleData.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/CellProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/portal/CellProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/Portal.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/portal/Portal.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/PortallizedSphereTree.h create mode 100644 engine/shared/library/sharedObject/src/shared/portal/SphereGrid.h create mode 100644 engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/property/LayerProperty.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/property/LayerProperty.h create mode 100644 engine/shared/library/sharedObject/src/shared/property/Property.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/property/Property.h create mode 100644 engine/shared/library/sharedObject/src/shared/property/PropertyId.h create mode 100644 engine/shared/library/sharedObject/src/shared/world/World.cpp create mode 100644 engine/shared/library/sharedObject/src/shared/world/World.h create mode 100644 engine/shared/library/sharedObject/src/win32/FirstSharedObject.cpp diff --git a/engine/shared/library/CMakeLists.txt b/engine/shared/library/CMakeLists.txt index ba4d0d11..55151ae9 100644 --- a/engine/shared/library/CMakeLists.txt +++ b/engine/shared/library/CMakeLists.txt @@ -12,6 +12,7 @@ add_subdirectory(sharedMemoryManager) add_subdirectory(sharedMessageDispatch) add_subdirectory(sharedNetwork) add_subdirectory(sharedNetworkMessages) +add_subdirectory(sharedObject) add_subdirectory(sharedRandom) add_subdirectory(sharedSynchronization) add_subdirectory(sharedThread) diff --git a/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h b/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h index b51f95c8..c5574f7f 100644 --- a/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h +++ b/engine/shared/library/sharedFoundation/src/shared/DataResourceList.h @@ -365,7 +365,7 @@ inline T * DataResourceList::reload(Iff &source) NOT_NULL(ms_loaded); const TemporaryCrcString sourceCrcString (source.getFileName(), true); - typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&sourceCrcString); + typename LoadedDataResourceMap::iterator iter = ms_loaded->find((const CrcString*)&sourceCrcString); if (iter == ms_loaded->end()) { DEBUG_WARNING(true, ("DataResourceList::reload: trying to reload unloaded resource %s!", source.getFileName())); @@ -388,7 +388,7 @@ inline const bool DataResourceList::isLoaded(const std::string & source) { NOT_NULL(ms_loaded); const TemporaryCrcString sourceCrcString (source.c_str (), true); - typename LoadedDataResourceMap::iterator iter = ms_loaded->find(&sourceCrcString); + typename LoadedDataResourceMap::iterator iter = ms_loaded->find((const CrcString*)&sourceCrcString); return (iter != ms_loaded->end()); } diff --git a/engine/shared/library/sharedObject/CMakeLists.txt b/engine/shared/library/sharedObject/CMakeLists.txt new file mode 100644 index 00000000..da3456cd --- /dev/null +++ b/engine/shared/library/sharedObject/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 2.8) + +project(sharedObject) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/private) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_Directory.h b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_Directory.h new file mode 100644 index 00000000..07ca7d4e --- /dev/null +++ b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_Directory.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationData_Directory.h" diff --git a/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_LocalDirectory.h b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_LocalDirectory.h new file mode 100644 index 00000000..c0b117a0 --- /dev/null +++ b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_LocalDirectory.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationData_LocalDirectory.h" diff --git a/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_RemoteDirectory.h b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_RemoteDirectory.h new file mode 100644 index 00000000..4271ae6a --- /dev/null +++ b/engine/shared/library/sharedObject/include/private/sharedObject/CustomizationData_RemoteDirectory.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationData_RemoteDirectory.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/AlterResult.h b/engine/shared/library/sharedObject/include/public/sharedObject/AlterResult.h new file mode 100644 index 00000000..eb40937e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/AlterResult.h @@ -0,0 +1 @@ +#include "../../src/shared/object/AlterResult.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/AlterScheduler.h b/engine/shared/library/sharedObject/include/public/sharedObject/AlterScheduler.h new file mode 100644 index 00000000..f7ccf1ad --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/AlterScheduler.h @@ -0,0 +1 @@ +#include "../../src/shared/object/AlterScheduler.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Appearance.h b/engine/shared/library/sharedObject/include/public/sharedObject/Appearance.h new file mode 100644 index 00000000..53fe49c7 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Appearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/Appearance.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplate.h b/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplate.h new file mode 100644 index 00000000..1ba0e4b8 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/AppearanceTemplate.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplateList.h b/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplateList.h new file mode 100644 index 00000000..d5fea625 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/AppearanceTemplateList.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/AppearanceTemplateList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptor.h b/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptor.h new file mode 100644 index 00000000..b4f55606 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptor.h @@ -0,0 +1 @@ +#include "../../src/shared/container/ArrangementDescriptor.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptorList.h b/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptorList.h new file mode 100644 index 00000000..8f22c159 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ArrangementDescriptorList.h @@ -0,0 +1 @@ +#include "../../src/shared/container/ArrangementDescriptorList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/BasicRangedIntCustomizationVariable.h b/engine/shared/library/sharedObject/include/public/sharedObject/BasicRangedIntCustomizationVariable.h new file mode 100644 index 00000000..f0b2e068 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/BasicRangedIntCustomizationVariable.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/BasicRangedIntCustomizationVariable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkId.h b/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkId.h new file mode 100644 index 00000000..b1c0c232 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkId.h @@ -0,0 +1 @@ +#include "../../src/shared/object/CachedNetworkId.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkIdArchive.h b/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkIdArchive.h new file mode 100644 index 00000000..1a79c49e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CachedNetworkIdArchive.h @@ -0,0 +1 @@ +#include "../../src/shared/object/CachedNetworkIdArchive.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CellProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/CellProperty.h new file mode 100644 index 00000000..107f726d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CellProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/portal/CellProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ConfigSharedObject.h b/engine/shared/library/sharedObject/include/public/sharedObject/ConfigSharedObject.h new file mode 100644 index 00000000..67c9bf6c --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ConfigSharedObject.h @@ -0,0 +1 @@ +#include "../../src/shared/core/ConfigSharedObject.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ContainedByProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/ContainedByProperty.h new file mode 100644 index 00000000..bfd31118 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ContainedByProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/container/ContainedByProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Container.h b/engine/shared/library/sharedObject/include/public/sharedObject/Container.h new file mode 100644 index 00000000..a747a4ff --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Container.h @@ -0,0 +1 @@ +#include "../../src/shared/container/Container.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Controller.h b/engine/shared/library/sharedObject/include/public/sharedObject/Controller.h new file mode 100644 index 00000000..77b6448d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Controller.h @@ -0,0 +1 @@ +#include "../../src/shared/controller/Controller.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationData.h b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationData.h new file mode 100644 index 00000000..e261a19d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationData.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationData.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationDataProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationDataProperty.h new file mode 100644 index 00000000..877be9a3 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationDataProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/property/CustomizationDataProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationIdManager.h b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationIdManager.h new file mode 100644 index 00000000..a99f6cd3 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationIdManager.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationIdManager.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationVariable.h b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationVariable.h new file mode 100644 index 00000000..7dc71e19 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/CustomizationVariable.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/CustomizationVariable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/DebugNotification.h b/engine/shared/library/sharedObject/include/public/sharedObject/DebugNotification.h new file mode 100644 index 00000000..171fab65 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/DebugNotification.h @@ -0,0 +1 @@ +#include "../../src/shared/object/DebugNotification.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/DebugYawedFloorNotification.h b/engine/shared/library/sharedObject/include/public/sharedObject/DebugYawedFloorNotification.h new file mode 100644 index 00000000..21559688 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/DebugYawedFloorNotification.h @@ -0,0 +1 @@ +#include "../../src/shared/object/DebugYawedFloorNotification.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Dynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/Dynamics.h new file mode 100644 index 00000000..c2b91f53 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Dynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/Dynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/FirstSharedObject.h b/engine/shared/library/sharedObject/include/public/sharedObject/FirstSharedObject.h new file mode 100644 index 00000000..066b370d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/FirstSharedObject.h @@ -0,0 +1 @@ +#include "../../src/shared/core/FirstSharedObject.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Hardpoint.h b/engine/shared/library/sharedObject/include/public/sharedObject/Hardpoint.h new file mode 100644 index 00000000..ddd57db5 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Hardpoint.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/Hardpoint.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/LayerProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/LayerProperty.h new file mode 100644 index 00000000..3c745961 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/LayerProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/property/LayerProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/LotManager.h b/engine/shared/library/sharedObject/include/public/sharedObject/LotManager.h new file mode 100644 index 00000000..8de62c0f --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/LotManager.h @@ -0,0 +1 @@ +#include "../../src/shared/lot/LotManager.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/LotType.h b/engine/shared/library/sharedObject/include/public/sharedObject/LotType.h new file mode 100644 index 00000000..51810399 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/LotType.h @@ -0,0 +1 @@ +#include "../../src/shared/lot/LotType.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/MemoryBlockManagedObject.h b/engine/shared/library/sharedObject/include/public/sharedObject/MemoryBlockManagedObject.h new file mode 100644 index 00000000..d0f2330e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/MemoryBlockManagedObject.h @@ -0,0 +1 @@ +#include "../../src/shared/object/MemoryBlockManagedObject.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/MovementTable.h b/engine/shared/library/sharedObject/include/public/sharedObject/MovementTable.h new file mode 100644 index 00000000..155e0421 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/MovementTable.h @@ -0,0 +1 @@ +#include "../../src/shared/movement/MovementTable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/NetworkController.h b/engine/shared/library/sharedObject/include/public/sharedObject/NetworkController.h new file mode 100644 index 00000000..a58f27b6 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/NetworkController.h @@ -0,0 +1 @@ +#include "../../src/shared/controller/NetworkController.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/NetworkIdManager.h b/engine/shared/library/sharedObject/include/public/sharedObject/NetworkIdManager.h new file mode 100644 index 00000000..5010b3b8 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/NetworkIdManager.h @@ -0,0 +1 @@ +#include "../../src/shared/object/NetworkIdManager.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearance.h b/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearance.h new file mode 100644 index 00000000..e5fb7498 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/NoRenderAppearance.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearanceTemplate.h b/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearanceTemplate.h new file mode 100644 index 00000000..208e4563 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/NoRenderAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/NoRenderAppearanceTemplate.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Object.h b/engine/shared/library/sharedObject/include/public/sharedObject/Object.h new file mode 100644 index 00000000..94f4dc49 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Object.h @@ -0,0 +1 @@ +#include "../../src/shared/object/Object.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectList.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectList.h new file mode 100644 index 00000000..6f659418 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectList.h @@ -0,0 +1 @@ +#include "../../src/shared/object/ObjectList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectNotification.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectNotification.h new file mode 100644 index 00000000..4a467d6b --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectNotification.h @@ -0,0 +1 @@ +#include "../../src/shared/object/ObjectNotification.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.def b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.def new file mode 100644 index 00000000..139a3c25 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.def @@ -0,0 +1 @@ +#include "../../src/shared/controller/ObjectSetMessage.def" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.h new file mode 100644 index 00000000..0c5274c1 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectSetMessage.h @@ -0,0 +1 @@ +#include "../../src/shared/controller/ObjectSetMessage.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplate.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplate.h new file mode 100644 index 00000000..1d2b3786 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/object/ObjectTemplate.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateCustomizationDataWriter.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateCustomizationDataWriter.h new file mode 100644 index 00000000..96d0b797 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateCustomizationDataWriter.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/ObjectTemplateCustomizationDataWriter.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateList.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateList.h new file mode 100644 index 00000000..c9d67c70 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectTemplateList.h @@ -0,0 +1 @@ +#include "../../src/shared/object/ObjectTemplateList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ObjectWatcherList.h b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectWatcherList.h new file mode 100644 index 00000000..3e589c90 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ObjectWatcherList.h @@ -0,0 +1 @@ +#include "../../src/shared/ObjectWatcherList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PaletteColorCustomizationVariable.h b/engine/shared/library/sharedObject/include/public/sharedObject/PaletteColorCustomizationVariable.h new file mode 100644 index 00000000..30f8fa77 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PaletteColorCustomizationVariable.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/PaletteColorCustomizationVariable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Portal.h b/engine/shared/library/sharedObject/include/public/sharedObject/Portal.h new file mode 100644 index 00000000..656b5aa8 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Portal.h @@ -0,0 +1 @@ +#include "../../src/shared/portal/Portal.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PortalProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/PortalProperty.h new file mode 100644 index 00000000..6f8586eb --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PortalProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/portal/PortalProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplate.h b/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplate.h new file mode 100644 index 00000000..c6d9f8d5 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/portal/PortalPropertyTemplate.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplateList.h b/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplateList.h new file mode 100644 index 00000000..89e6bc06 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PortalPropertyTemplateList.h @@ -0,0 +1 @@ +#include "../../src/shared/portal/PortalPropertyTemplateList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PortallizedSphereTree.h b/engine/shared/library/sharedObject/include/public/sharedObject/PortallizedSphereTree.h new file mode 100644 index 00000000..f9e7ec7e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PortallizedSphereTree.h @@ -0,0 +1,2 @@ +#include "../../src/shared/portal/PortallizedSphereTree.h" + diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Property.h b/engine/shared/library/sharedObject/include/public/sharedObject/Property.h new file mode 100644 index 00000000..92168d86 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Property.h @@ -0,0 +1 @@ +#include "../../src/shared/property/Property.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PropertyId.h b/engine/shared/library/sharedObject/include/public/sharedObject/PropertyId.h new file mode 100644 index 00000000..cbd58dd5 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PropertyId.h @@ -0,0 +1 @@ +#include "../../src/shared/property/PropertyId.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/PulseDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/PulseDynamics.h new file mode 100644 index 00000000..e7488435 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/PulseDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/PulseDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/RangedIntCustomizationVariable.h b/engine/shared/library/sharedObject/include/public/sharedObject/RangedIntCustomizationVariable.h new file mode 100644 index 00000000..b41e112d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/RangedIntCustomizationVariable.h @@ -0,0 +1 @@ +#include "../../src/shared/customization/RangedIntCustomizationVariable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/RotationDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/RotationDynamics.h new file mode 100644 index 00000000..9e0f7931 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/RotationDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/RotationDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/ScheduleData.h b/engine/shared/library/sharedObject/include/public/sharedObject/ScheduleData.h new file mode 100644 index 00000000..b30c398d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/ScheduleData.h @@ -0,0 +1 @@ +#include "../../src/shared/object/ScheduleData.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SeesawDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/SeesawDynamics.h new file mode 100644 index 00000000..1634fe67 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SeesawDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/SeesawDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SetupSharedObject.h b/engine/shared/library/sharedObject/include/public/sharedObject/SetupSharedObject.h new file mode 100644 index 00000000..f9881f2e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SetupSharedObject.h @@ -0,0 +1 @@ +#include "../../src/shared/core/SetupSharedObject.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SimpleDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/SimpleDynamics.h new file mode 100644 index 00000000..8e3342f1 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SimpleDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/SimpleDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptor.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptor.h new file mode 100644 index 00000000..f492b62e --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptor.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotDescriptor.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptorList.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptorList.h new file mode 100644 index 00000000..6d751ce0 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotDescriptorList.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotDescriptorList.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotId.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlotId.h new file mode 100644 index 00000000..53885eb8 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotId.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotId.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdArchive.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdArchive.h new file mode 100644 index 00000000..f44b89db --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdArchive.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotIdArchive.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdManager.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdManager.h new file mode 100644 index 00000000..103c59d3 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotIdManager.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotIdManager.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlotType.def b/engine/shared/library/sharedObject/include/public/sharedObject/SlotType.def new file mode 100644 index 00000000..8deb581d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlotType.def @@ -0,0 +1 @@ +#include "../../src/shared/container/SlotType.def" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainer.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainer.h new file mode 100644 index 00000000..0dd18cb7 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainer.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlottedContainer.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainmentProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainmentProperty.h new file mode 100644 index 00000000..ad58afd1 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SlottedContainmentProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/container/SlottedContainmentProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SphereGrid.h b/engine/shared/library/sharedObject/include/public/sharedObject/SphereGrid.h new file mode 100644 index 00000000..9502e156 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SphereGrid.h @@ -0,0 +1,2 @@ +#include "../../src/shared/portal/SphereGrid.h" + diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/SpringDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/SpringDynamics.h new file mode 100644 index 00000000..a47c9663 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/SpringDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/SpringDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/StateDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/StateDynamics.h new file mode 100644 index 00000000..2a1a88c4 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/StateDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/StateDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/StructureFootprint.h b/engine/shared/library/sharedObject/include/public/sharedObject/StructureFootprint.h new file mode 100644 index 00000000..84158cc8 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/StructureFootprint.h @@ -0,0 +1 @@ +#include "../../src/shared/lot/StructureFootprint.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/TextAppearance.h b/engine/shared/library/sharedObject/include/public/sharedObject/TextAppearance.h new file mode 100644 index 00000000..42148839 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/TextAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/TextAppearance.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/TrackingDynamics.h b/engine/shared/library/sharedObject/include/public/sharedObject/TrackingDynamics.h new file mode 100644 index 00000000..3b51bbf5 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/TrackingDynamics.h @@ -0,0 +1 @@ +#include "../../src/shared/dynamics/TrackingDynamics.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/Tweakable.h b/engine/shared/library/sharedObject/include/public/sharedObject/Tweakable.h new file mode 100644 index 00000000..daf33893 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/Tweakable.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/Tweakable.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainer.h b/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainer.h new file mode 100644 index 00000000..59d17069 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainer.h @@ -0,0 +1 @@ +#include "../../src/shared/container/VolumeContainer.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainmentProperty.h b/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainmentProperty.h new file mode 100644 index 00000000..1e6b650d --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/VolumeContainmentProperty.h @@ -0,0 +1 @@ +#include "../../src/shared/container/VolumeContainmentProperty.h" diff --git a/engine/shared/library/sharedObject/include/public/sharedObject/World.h b/engine/shared/library/sharedObject/include/public/sharedObject/World.h new file mode 100644 index 00000000..e5964f79 --- /dev/null +++ b/engine/shared/library/sharedObject/include/public/sharedObject/World.h @@ -0,0 +1 @@ +#include "../../src/shared/world/World.h" diff --git a/engine/shared/library/sharedObject/src/CMakeLists.txt b/engine/shared/library/sharedObject/src/CMakeLists.txt new file mode 100644 index 00000000..6dd18070 --- /dev/null +++ b/engine/shared/library/sharedObject/src/CMakeLists.txt @@ -0,0 +1,196 @@ + +set(SHARED_SOURCES + shared/ObjectWatcherList.cpp + shared/ObjectWatcherList.h + + shared/appearance/Appearance.cpp + shared/appearance/Appearance.h + shared/appearance/AppearanceTemplate.cpp + shared/appearance/AppearanceTemplate.h + shared/appearance/AppearanceTemplateList.cpp + shared/appearance/AppearanceTemplateList.h + shared/appearance/Hardpoint.cpp + shared/appearance/Hardpoint.h + shared/appearance/NoRenderAppearance.cpp + shared/appearance/NoRenderAppearance.h + shared/appearance/NoRenderAppearanceTemplate.cpp + shared/appearance/NoRenderAppearanceTemplate.h + shared/appearance/TextAppearance.cpp + shared/appearance/TextAppearance.h + shared/appearance/Tweakable.cpp + shared/appearance/Tweakable.h + + shared/container/ArrangementDescriptor.cpp + shared/container/ArrangementDescriptor.h + shared/container/ArrangementDescriptorList.cpp + shared/container/ArrangementDescriptorList.h + shared/container/ContainedByProperty.cpp + shared/container/ContainedByProperty.h + shared/container/Container.cpp + shared/container/Container.h + shared/container/SlotDescriptor.cpp + shared/container/SlotDescriptor.h + shared/container/SlotDescriptorList.cpp + shared/container/SlotDescriptorList.h + shared/container/SlotIdArchive.h + shared/container/SlotId.cpp + shared/container/SlotId.h + shared/container/SlotIdManager.cpp + shared/container/SlotIdManager.h + shared/container/SlottedContainer.cpp + shared/container/SlottedContainer.h + shared/container/SlottedContainmentProperty.cpp + shared/container/SlottedContainmentProperty.h + shared/container/SlotType.def + shared/container/VolumeContainer.cpp + shared/container/VolumeContainer.h + shared/container/VolumeContainmentProperty.cpp + shared/container/VolumeContainmentProperty.h + + shared/controller/Controller.cpp + shared/controller/Controller.h + shared/controller/NetworkController.cpp + shared/controller/NetworkController.h + shared/controller/ObjectSetMessage.def + shared/controller/ObjectSetMessage.h + + shared/core/ConfigSharedObject.cpp + shared/core/ConfigSharedObject.h + shared/core/FirstSharedObject.h + shared/core/SetupSharedObject.cpp + shared/core/SetupSharedObject.h + + shared/customization/BasicRangedIntCustomizationVariable.cpp + shared/customization/BasicRangedIntCustomizationVariable.h + shared/customization/CustomizationData.cpp + shared/customization/CustomizationData_Directory.h + shared/customization/CustomizationData.h + shared/customization/CustomizationData_LocalDirectory.cpp + shared/customization/CustomizationData_LocalDirectory.h + shared/customization/CustomizationData_RemoteDirectory.cpp + shared/customization/CustomizationData_RemoteDirectory.h + shared/customization/CustomizationIdManager.cpp + shared/customization/CustomizationIdManager.h + shared/customization/CustomizationVariable.cpp + shared/customization/CustomizationVariable.h + shared/customization/ObjectTemplateCustomizationDataWriter.cpp + shared/customization/ObjectTemplateCustomizationDataWriter.h + shared/customization/PaletteColorCustomizationVariable.cpp + shared/customization/PaletteColorCustomizationVariable.h + shared/customization/RangedIntCustomizationVariable.cpp + shared/customization/RangedIntCustomizationVariable.h + + shared/dynamics/Dynamics.cpp + shared/dynamics/Dynamics.h + shared/dynamics/RotationDynamics.cpp + shared/dynamics/RotationDynamics.h + shared/dynamics/SeesawDynamics.cpp + shared/dynamics/SeesawDynamics.h + shared/dynamics/SimpleDynamics.cpp + shared/dynamics/SimpleDynamics.h + shared/dynamics/SpringDynamics.cpp + shared/dynamics/SpringDynamics.h + shared/dynamics/StateDynamics.cpp + shared/dynamics/StateDynamics.h + shared/dynamics/TrackingDynamics.cpp + shared/dynamics/TrackingDynamics.h + + shared/lot/LotManager.cpp + shared/lot/LotManager.h + shared/lot/LotType.h + shared/lot/StructureFootprint.cpp + shared/lot/StructureFootprint.h + + shared/movement/MovementTable.cpp + shared/movement/MovementTable.h + + shared/object/AlterResult.cpp + shared/object/AlterResult.h + shared/object/AlterScheduler.cpp + shared/object/AlterScheduler.h + shared/object/CachedNetworkIdArchive.h + shared/object/CachedNetworkId.cpp + shared/object/CachedNetworkId.h + shared/object/DebugNotification.cpp + shared/object/DebugNotification.h + shared/object/DebugYawedFloorNotification.cpp + shared/object/DebugYawedFloorNotification.h + shared/object/MemoryBlockManagedObject.cpp + shared/object/MemoryBlockManagedObject.h + shared/object/NetworkIdManager.cpp + shared/object/NetworkIdManager.h + shared/object/Object.cpp + shared/object/Object.h + shared/object/ObjectList.cpp + shared/object/ObjectList.h + shared/object/ObjectNotification.cpp + shared/object/ObjectNotification.h + shared/object/ObjectTemplate.cpp + shared/object/ObjectTemplate.h + shared/object/ObjectTemplateList.cpp + shared/object/ObjectTemplateList.h + shared/object/ScheduleData.cpp + shared/object/ScheduleData.h + + shared/portal/CellProperty.cpp + shared/portal/CellProperty.h + shared/portal/Portal.cpp + shared/portal/Portal.h + shared/portal/PortallizedSphereTree.h + shared/portal/PortalProperty.cpp + shared/portal/PortalProperty.h + shared/portal/PortalPropertyTemplate.cpp + shared/portal/PortalPropertyTemplate.h + shared/portal/PortalPropertyTemplateList.cpp + shared/portal/PortalPropertyTemplateList.h + shared/portal/SphereGrid.h + + shared/property/CustomizationDataProperty.cpp + shared/property/CustomizationDataProperty.h + shared/property/LayerProperty.cpp + shared/property/LayerProperty.h + shared/property/Property.cpp + shared/property/Property.h + shared/property/PropertyId.h + + shared/world/World.cpp + shared/world/World.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/FirstSharedObject.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32) +else() + set(PLATFORM_SOURCES "") +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCollision/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedGame/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedLog/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMessageDispatch/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedNetworkMessages/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedSynchronization/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedTerrain/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/archive/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/localization/include + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/unicode/include +) + +add_library(sharedObject STATIC + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.cpp b/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.cpp new file mode 100644 index 00000000..a2cb6e67 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.cpp @@ -0,0 +1,457 @@ +// ====================================================================== +// +// ObjectWatcherList.cpp +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectWatcherList.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/Object.h" +#include "sharedFoundation/Watcher.h" + +#include + +// ====================================================================== + +namespace ObjectWatcherListNamespace +{ + void setRegionOfInfluenceEnabled(Object const * const object, bool const enabled, bool skipCell) + { + if (skipCell && NULL != object->getCellProperty()) + return; + + object->setRegionOfInfluenceEnabled(enabled); + + for (int i = 0; i < object->getNumberOfChildObjects(); ++i) + setRegionOfInfluenceEnabled(object->getChildObject(i), enabled, skipCell); + } +} + +// ====================================================================== +// Construct an ObjectWatcherList + +ObjectWatcherList::ObjectWatcherList (int initialVectorSize) : +m_altering (false), +m_objectVector (new ObjectVector), +m_alterSafeObjectVector (new ObjectVector), +m_skipCellRegionOfInfluence(false) +{ + DEBUG_FATAL(initialVectorSize < 0, ("negative vector size")); + + // Reserve the requested amount of entries to reduce further allocation + + m_objectVector->reserve (static_cast (initialVectorSize)); + m_alterSafeObjectVector->reserve (static_cast (initialVectorSize)); +} + +// ---------------------------------------------------------------------- +/** + * Destroy an ObjectWatcherList. + */ + +ObjectWatcherList::~ObjectWatcherList(void) +{ + delete m_objectVector; + m_objectVector = 0; + delete m_alterSafeObjectVector; + m_alterSafeObjectVector = 0; +} + +// ---------------------------------------------------------------------- +/** + * Add an Object to the ObjectWatcherList. + * + * This routine will call Fatal in debug compiles if it is passed a NULL + * object. + * + * This routine will call Fatal in debug compiles if the object list + * overflows. + * + * @param objectToAdd Object to add to the ObjectWatcherList + */ + +void ObjectWatcherList::addObject(Object & objectToAdd) +{ + m_objectVector->push_back(Watcher(&objectToAdd)); +} + +// ---------------------------------------------------------------------- +/** + * Remove an Object from the ObjectWatcherList. + * + * This routine will call Fatal in debug compiles if it is passed a NULL + * object. + * + * @param objectToRemove Pointer to the object to remove + */ + +void ObjectWatcherList::removeObject(const Object & objectToRemove) +{ + int index = 0; + if (find(objectToRemove, &index)) + removeObjectByIndex(objectToRemove, index); +} + +// ---------------------------------------------------------------------- + +void ObjectWatcherList::removeObjectByIndex (const Object & object, int index) +{ + DEBUG_FATAL(index >= static_cast(m_objectVector->size()), ("Index out of range")); + DEBUG_FATAL((*m_objectVector)[static_cast(index)] != &object, ("Object is not the one indexed.")); + + // Replace the found entry with the entry from the back of the vector + // so there is no shifting of the items in the vector. + (*m_objectVector)[static_cast(index)] = m_objectVector->back(); + + // Remove the last item in the vector. + m_objectVector->pop_back(); + + // NULL the object from the alter-safe object list. + uint size = m_alterSafeObjectVector->size(); + for (uint i = 0; i < size; ++i) + { + if ((*m_alterSafeObjectVector)[i] == &object) + { + (*m_alterSafeObjectVector)[i] = NULL; + return; + } + } +} + + +// ---------------------------------------------------------------------- +/** + * Remove all Objects from the ObjectWatcherList. + * + * Removes all Objects from the ObjectWatcherList + * + * This routine may not be called between prepareToAlter() and alter(). + * + * If deleteObjects is true, this routine will call delete for all objects in the list + * + * @param deleteObjects Flag to delete all objects when they are removed + */ + +void ObjectWatcherList::removeAll (bool deleteObjects) +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + if (deleteObjects) + { + ObjectVector::iterator end = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + delete i->getPointer(); + } + + m_objectVector->clear(); +} + +// ---------------------------------------------------------------------- + +void ObjectWatcherList::addToWorld() +{ + ObjectVector::iterator iEnd = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != iEnd; ++i) + { + Object * const object = (*i); + if (object) + object->addToWorld(); + } +} + +// ---------------------------------------------------------------------- + +void ObjectWatcherList::removeFromWorld() +{ + ObjectVector::iterator iEnd = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != iEnd; ++i) + { + Object * const object = (*i); + if (object) + object->removeFromWorld(); + } +} + +// ---------------------------------------------------------------------- +/** + * Prepare to call alter() on this object list. + * + * This routine must be called before calling alter(). It will copy setup + * the ObjectWatcherList so that objects may be added and removed from the ObjectWatcherList + * during the alter() without affecting that frame's list of objects that are + * are being altered. + */ + +void ObjectWatcherList::prepareToAlter(void) +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + m_altering = true; + + // Duplicate the object vector + + (*m_alterSafeObjectVector) = (*m_objectVector); +} + +// ---------------------------------------------------------------------- +/** + * Call alter() for all objects in the ObjectWatcherList. + * + * prepareToAlter() must be called before this routine can be called. + * + * This routine will simply iterate over all the objects in the ObjectWatcherList + * and call their alter routines with the specified time. + * + * @param time Time to pass to each Object's alter routine + * @see ObjectWatcherList::prepareToAlter() + */ + +void ObjectWatcherList::alter(real time) +{ + DEBUG_FATAL(!m_altering, ("prepareToAlter was not called")); + + for (size_t i = 0; i < m_alterSafeObjectVector->size(); ++i) + { + // Cache the object pointer because the iter value may be nulled if the object, + // is removed from the list withing its alter() + + Object * const obj = (*m_alterSafeObjectVector)[i]; + if (!obj || !obj->isInitialized()) + continue; + + float const alterResult = obj->alter(time); + if (alterResult == AlterResult::cms_kill) + { + // alter() return false, so remove and delete the object + + // Make sure the object is still in the object list before removing it + + if ((*m_alterSafeObjectVector)[i] != NULL) + { + removeObject(*obj); + } + + delete obj; + } + } + + m_alterSafeObjectVector->clear(); + m_altering = false; +} + +// ---------------------------------------------------------------------- +/** + * Call conclude() for all objects in the ObjectWatcherList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectWatcherList + * and call their conclude routines with the specified time. + */ + +void ObjectWatcherList::conclude() +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + Object * const object = (*i); + if (object && object->isInitialized()) + object->conclude(); + } +} + +// ---------------------------------------------------------------------- +/** + * Call addToScene() for all objects in the ObjectWatcherList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectWatcherList + * and call their addToScene() routine with the specified camera. + * + * @param camera Camera rendering the scene. + * @param excludedObject Object to exclude from the scene. + */ + +void ObjectWatcherList::setRegionOfInfluenceEnabled(bool enabled) const +{ + ObjectVector::iterator end = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + Object const * const object = (*i); + if (object) + ObjectWatcherListNamespace::setRegionOfInfluenceEnabled(object, enabled, m_skipCellRegionOfInfluence); + } +} + +// ---------------------------------------------------------------------- +/** + * Call addToScene() for all objects in the ObjectWatcherList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectWatcherList + * and call their addToScene() routine with the specified camera. + * + * @param camera Camera rendering the scene. + * @param excludedObject Object to exclude from the scene. + */ + +void ObjectWatcherList::render(const Object *excludedObject) const +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + const ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + Object *const object = *i; + if (object && (object != excludedObject)) + { + const Appearance *const appearance = object->getAppearance(); + if (appearance) + { + appearance->setTransform_w(object->getTransform_o2w()); + appearance->objectListCameraRender(); + } + } + } +} + +// ---------------------------------------------------------------------- +/** + * Find the index of an object in an object list. + * + * Accepts an optional index to be used to return the object's index + * in the object list. + * + * This routine will simply iterate over all the objects in the ObjectWatcherList + * searching for the objectToCheck, and returns true with the index if + * found, and false otherwise. + * + * @param objectToCheck Object to find + * @param index Object's index in the object list + */ + +bool ObjectWatcherList::find(const Object & objectToCheck, int *index) const +{ + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + const Object * const obj = (*i); + + if (obj == &objectToCheck) + { + if (index) + *index = std::distance(m_objectVector->begin(), i); + return true; + } + + } + + return false; +} + +//---------------------------------------------------------------------- + +int ObjectWatcherList::removeNulls () +{ + int count = 0; + for (ObjectVector::iterator i = m_objectVector->begin(); i != m_objectVector->end();) + { + const Object * const obj = (*i); + + if (obj) + ++i; + else + { + ++count; + i = m_objectVector->erase (i); + } + } + + return count; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of objects contained in the object list. + * + * @return The number of objects contained in the object list + */ + +int ObjectWatcherList::getNumberOfObjects(void) const +{ + return static_cast (m_objectVector->size()); +} + +// ---------------------------------------------------------------------- +/** + * Get an object in the object list. + * + * @param index Index of the object in the object list + */ + +Object *ObjectWatcherList::operator [](int index) +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get a const object from the object list. + * + * @param index Index of the object in the object list + */ + +const Object *ObjectWatcherList::operator [](int index) const +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get an object in the object list. + * + * @param index Index of the object in the object list + */ + +Object *ObjectWatcherList::getObject(int index) +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get a const object from the object list. + * + * @param index Index of the object in the object list + */ + +const Object *ObjectWatcherList::getObject(int index) const +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +//---------------------------------------------------------------------- + +void ObjectWatcherList::setSkipCellRegionOfInfluence(bool skip) +{ + m_skipCellRegionOfInfluence = skip; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.h b/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.h new file mode 100644 index 00000000..9c6307fd --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/ObjectWatcherList.h @@ -0,0 +1,76 @@ +// ====================================================================== +// +// ObjectWatcherList.h +// copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ObjectWatcherList_H +#define INCLUDED_ObjectWatcherList_H + +// ====================================================================== + +template class Watcher; +class Object; +class Camera; + +// ====================================================================== +// Contain a list of watchers to objects. +// +// Objects may exist in more than one ObjectWatcherList simultaneously. + +class ObjectWatcherList +{ +public: + + explicit ObjectWatcherList (int initialVectorSize=0); + ~ObjectWatcherList (); + + void addObject (Object & object); + void removeObject (const Object & object); + int removeNulls (); + + void removeAll (bool deleteObjects=false); + + int getNumberOfObjects () const; + + Object * getObject (int index); + const Object * getObject (int index) const; + + Object * operator [] (int index); + const Object * operator [] (int index) const; + + bool find (const Object & objectToCheck, int* index=0) const; + void removeObjectByIndex (const Object &, int index); + + void addToWorld (); + void removeFromWorld (); + + void prepareToAlter (); + void alter (real time); + void conclude (); + + void setRegionOfInfluenceEnabled (bool enabled) const; + void render (const Object *omitObject) const; + + void setSkipCellRegionOfInfluence(bool skip); + +private: + + typedef stdvector >::fwd ObjectVector; + bool m_altering; + ObjectVector * m_objectVector; + ObjectVector * m_alterSafeObjectVector; + bool m_skipCellRegionOfInfluence; + +private: + + // disable these routines + ObjectWatcherList (const ObjectWatcherList &); + ObjectWatcherList & operator = (const ObjectWatcherList &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Appearance.cpp b/engine/shared/library/sharedObject/src/shared/appearance/Appearance.cpp new file mode 100644 index 00000000..e1acba39 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Appearance.cpp @@ -0,0 +1,896 @@ +// ====================================================================== +// +// Appearance.cpp +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Appearance.h" + +#include "sharedCollision/CollideParameters.h" +#include "sharedCollision/ExtentList.h" +#include "sharedCollision/Extent.h" +#include "sharedCollision/FloorManager.h" +#include "sharedCollision/Floor.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/DebugShapeRenderer.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/CustomizationDataProperty.h" +#include "sharedObject/Hardpoint.h" +#include "sharedObject/Object.h" + +// ====================================================================== + +namespace AppearanceNamespace +{ +#ifdef _DEBUG + bool ms_drawAppearanceFrames; +#endif + + int ms_frameNumber; + bool ms_renderHardpoints; + bool ms_renderHardpointNames; + Appearance::RenderHardpointFunction ms_renderHardpointFunction; + + bool s_renderEnabled = true; + + //---------------------------------------------------------------------- + +} + +using namespace AppearanceNamespace; + +// ====================================================================== + +void Appearance::install() +{ +#ifdef _DEBUG + DebugFlags::registerFlag(ms_drawAppearanceFrames, "SharedObject", "drawAppearanceFrames"); + DebugFlags::registerFlag(ms_renderHardpoints, "SharedObject", "renderHardpoints"); + DebugFlags::registerFlag(ms_renderHardpointNames, "SharedObject", "renderHardpointNames"); +#endif +} + +// ---------------------------------------------------------------------- + +void Appearance::beginNewFrame() +{ + ++ms_frameNumber; +} + +// ---------------------------------------------------------------------- + +void Appearance::setRenderHardpointFunction(RenderHardpointFunction renderHardpointFunction) +{ + ms_renderHardpointFunction = renderHardpointFunction; +} + +// ====================================================================== +// Construct a new Appearance + +Appearance::Appearance(const AppearanceTemplate *newAppearanceTemplate) : + m_appearanceTemplate(AppearanceTemplateList::fetch(newAppearanceTemplate)), + m_extent(m_appearanceTemplate ? ExtentList::fetch(m_appearanceTemplate->getExtent()) : NULL), + m_owner(NULL), + m_renderedFrameNumber(0), + m_scale(Vector::xyz111), + m_keepAlive(false), + m_useRenderEffectsFlag(false), + m_shadowBlobAllowed(false) +{ +} + +// ---------------------------------------------------------------------- +/** + * Destroy an Appearance. + * + * This routine will release the AppearanceTemplate used by this Appearance. + */ + +Appearance::~Appearance() +{ + ExtentList::release(m_extent); + m_extent = NULL; + + if (m_appearanceTemplate) + { + AppearanceTemplateList::release(m_appearanceTemplate); + m_appearanceTemplate = NULL; + } + + m_owner = NULL; +} + +// ---------------------------------------------------------------------- +/** + * Check if the data for this appearance has been loaded. + */ + +bool Appearance::isLoaded() const +{ + return true; +} + +// ---------------------------------------------------------------------- +/** + * Alter the appearance specifying the amount of time that has passed. + * + * This routine can be used to modify the appearance before it's rendered + */ + +float Appearance::alter(float deltaTime) +{ + UNREF(deltaTime); + return (isAlive() ? AlterResult::cms_keepNoAlter : AlterResult::cms_kill); +} + +// ---------------------------------------------------------------------- +/** + * Get an Extent to be used for selection of this object in tools + * + * This routine may be overloaded in derived classes. + */ + +const Extent *Appearance::getSelectionExtent() const +{ + return getExtent(); +} + +// ---------------------------------------------------------------------- +/** + * Get the Extent of this Appearance. + * + * This routine may be overloaded in derived classes. + */ + +const Extent *Appearance::getExtent() const +{ + return m_extent; +} + +// ---------------------------------------------------------------------- +/** + * Set a new Extent for this Appearance. + * + * The current extent will be released. + * + * @param newExtent New extent for this Appearance + */ + +void Appearance::setExtent(const Extent *extent) +{ + ExtentList::release(m_extent); + m_extent = extent; + + extentChanged(); +} + +// ---------------------------------------------------------------------- +/** + * Get the tangible axial box, if applicable, for systems such as targeting. + * Derived appearances can choose how much of the appearance contributes. + */ + +AxialBox const Appearance::getTangibleExtent() const +{ + return AxialBox(); +} + +// ---------------------------------------------------------------------- +/** + * Return the bounding sphere for the Appearance. + * + * This routine may be overloaded in derived classes. By default it + * gets the spheere from its extents. If the extent doesn't exist, it + * returns the zero sphere + * + * @return The bounding sphere in object space. + */ + +const Sphere &Appearance::getSphere() const +{ + const Extent *const extent = getExtent(); + return extent ? extent->getSphere() : Sphere::zero; +} + +// ---------------------------------------------------------------------- + +void Appearance::addToWorld() +{ + DPVS::Object *dpvsObject = getDpvsObject(); + if (dpvsObject) + { + NOT_NULL(m_owner); + m_owner->addDpvsObject(dpvsObject); + } +} + +// ---------------------------------------------------------------------- + +void Appearance::removeFromWorld() +{ + DPVS::Object *dpvsObject = getDpvsObject(); + if (dpvsObject) + { + Object *owner = getOwner(); + if (owner) + { + owner->removeDpvsObject(dpvsObject); + } + } +} + +// ---------------------------------------------------------------------- + +void Appearance::preRender() const +{ +} + +// ---------------------------------------------------------------------- + +void Appearance::render() const +{ +#ifdef _DEBUG + const Object *owner = getOwner(); + if (owner) + { + DebugShapeRenderer * const renderer = DebugShapeRenderer::create(owner); + drawDebugShapes(renderer); + delete renderer; + + if (ms_renderHardpoints && ms_renderHardpointFunction) + { + for (int i = 0; i < getHardpointCount(); ++i) + { + Hardpoint const & hardpoint = getHardpoint(i); + + Transform transform_h2w; + transform_h2w.multiply(getTransform_w(), hardpoint.getTransform()); + + ms_renderHardpointFunction(transform_h2w, ms_renderHardpointNames, hardpoint.getName().getString()); + } + } + } +#endif +} + +//---------------------------------------------------------------------- + +void Appearance::objectListCameraRenderDescend(Object const & obj) +{ + //-- don't descend through cells + if (NULL != obj.getCellProperty()) + return; + + int const childCount = obj.getNumberOfChildObjects(); + for (int i = 0; i < childCount; ++i) + { + // Get the child object. + Object const *const childObject = obj.getChildObject(i); + if (!childObject) + continue; + + if (!childObject->isActive()) + continue; + + // Setup child object appearance to world transform. + const_cast(childObject)->setTransform_a2w(childObject->getTransform_o2w()); + + // Render its appearance. + const Appearance *const childAppearance = childObject->getAppearance(); + if (childAppearance) + childAppearance->objectListCameraRender(); + else + objectListCameraRenderDescend(*childObject); + } +} + +// ---------------------------------------------------------------------- + +void Appearance::objectListCameraRender() const +{ + if (!usesRenderEffectsFlag() || canRenderEffects()) + { + //-- Render this appearance. + render(); + + setRenderedThisFrame(); + + //-- Render the owner's child objects. + Object const *const owner = getOwner(); + if (!owner) + return; + + int const childCount = owner->getNumberOfChildObjects(); + for (int i = 0; i < childCount; ++i) + { + // Get the child object. + Object const *const childObject = owner->getChildObject(i); + if (!childObject) + continue; + + if (!childObject->isActive()) + continue; + + const Appearance *const childAppearance = childObject->getAppearance(); + if (childAppearance) + { + // Setup child object appearance to world transform. + childAppearance->setTransform_w(childObject->getTransform_o2w()); + + // Render its appearance. + childAppearance->objectListCameraRender(); + } + else + objectListCameraRenderDescend(*childObject); + } + } +} + +// ---------------------------------------------------------------------- + +void Appearance::setTexture(Tag /*tag*/, const Texture & /*texture*/) +{ +} + +// ---------------------------------------------------------------------- +/** + * Cast a ray through object space and return the result of the collision (if any) to result + * + * @param start_o Object space start position of the ray + * @param end_o Object space end position of the ray + * @param collideParameters Struct which contains information about the type and quality of collision + * @param result Struct which contains information about the collision + * @return Whether or not a collision occurred + */ + +bool Appearance::collide(Vector const & /*start_o*/, Vector const & /*end_o*/, CollideParameters const & /*collideParameters*/, CollisionInfo & /*result*/) const +{ + return false; +} + +// ---------------------------------------------------------------------- + +bool Appearance::implementsCollide() const +{ + return false; +} + +// ---------------------------------------------------------------------- +/** + * Set the new owning object associated with this appearance. + * + * There is a 1-1 correpsondence between Object instances and Appearance + * instances. This function is called to set the Object instance + * associated with this Appearance instance. + * + * This implementation checks the owner Object instance for a + * CustomizationDataProperty. If there is such a property, this + * function will invoke Appearance::setCustomizationData() with the + * appropriate value. If the property doesn't exist, this function + * will invoke Appearance::setCustomizationData() with NULL. Note if + * the caller sets the CustomizationDataProperty for an Object after + * associating the Object instance with the appearance, the caller is + * responsible for calling Appearance::setCustomizationData(). + * + * Implementers overriding this function must ensure they chain back + * to this function as it performs necessary state modification. + * + * -TRF- I'm not sure why this is virtual. I think this probably needs + * to be made non virtual. Currently it is mandatory for descendants + * that override this function to chain back to this function to handle + * the CustomizationData setup. + */ + +void Appearance::setOwner(Object* owner) +{ + //-- keep track of owner object. + m_owner = owner; + + // DBE - This was added to mimic the behavior of when the appearance-to-world + // transform was stored in Object instead of Appearance. + if (owner) + { + Appearance *ownerAppearance = owner->getAppearance(); + if (!ownerAppearance) + { + setTransform_w(owner->getTransform_o2w()); + } + else if (ownerAppearance!=this) + { + setTransform_w(ownerAppearance->getTransform_w()); + } + } + + //-- retrieve customization data for new owner + CustomizationData *customizationData = 0; + + if (owner) + { + // get the property + CustomizationDataProperty *const property = safe_cast(owner->getProperty(CustomizationDataProperty::getClassPropertyId())); + if (property) + { + // retrieve the customization data from the property + customizationData = property->fetchCustomizationData(); + } + } + + //-- set the CustomizationData + setCustomizationData(customizationData); + + //-- release local reference + if (customizationData) + customizationData->release(); + + //-- clear the rendered frame number + m_renderedFrameNumber = 0; +} + +// ---------------------------------------------------------------------- + +void Appearance::setAlpha(bool const /* opaqueEnabled */, float const /* opaqueAlpha*/, bool const /* alphaEnabled */, float const /* alphaAlpha */) +{ +} + +// ---------------------------------------------------------------------- + +void Appearance::setTransform_w(const Transform &t) const +{ + m_appearanceToWorld=t; +} + +// ---------------------------------------------------------------------- + +const char * Appearance::getFloorName () const +{ + if (m_appearanceTemplate) + return m_appearanceTemplate->getFloorName(); + + return NULL; +} + +// ---------------------------------------------------------------------- +/** + * Set the CustomizationData associated with this Appearance instance. + * + * This function's primary purpose is to be overridden. It allows + * derived Appearance classes to do something with the CustomizationData + * when the CustomizationData instance is set or changed. The CustomizationData + * instance changes when the owning Object is initially set or changed + * to a new Object instance. + * + * Derived classes are not required to chain call this function. + * + * Callers need only invoke this function directly if CustomizationData + * is initialized for the owning Object after Appearance::setOwner() is + * called. The only feasible time this should happen is when the Object + * and Appearance instances are created and associated prior to creation + * of CustomizationData. + * + * @param customizationData the new CustomizationData instance associated + * with this Appearance instance. + */ + +void Appearance::setCustomizationData(CustomizationData * /* customizationData */) +{ +} + +// ---------------------------------------------------------------------- +/** + * Add all CustomizationData variables influencing this Appearance instance + * to the given CustomizationData instance. + * + * This is primarily useful as a mechanism for tools. The game should already + * know which customization variables it has enabled for objects via the + * ObjectTemplate system. + * + * Derived classes do not need to chain down to this function. + * + * Implementers: there are no guarantees as to the order of calls between + * setCustomizationData() and this function. In other words, the implementation + * should use the given CustomizationData arg to add variables. + * + * @param customizationData the CustomizationData instance to which new + * variables will be added. Assumed to be empty + * on entry. + */ + +void Appearance::addCustomizationVariables(CustomizationData & /* customizationData */) const +{ +} + +// ---------------------------------------------------------------------- + +void Appearance::setKeepAlive(bool const keepAlive) +{ + m_keepAlive = keepAlive; +} + +// ---------------------------------------------------------------------- + +bool Appearance::isAlive() const +{ + return m_keepAlive ? true : realIsAlive(); +} + +// ---------------------------------------------------------------------- + +bool Appearance::realIsAlive() const +{ + return true; +} + +// ---------------------------------------------------------------------- +/** + * Find and return the transform for the given hardpoint. + * + * The transform is returned in local Object (Appearance) space. It is a + * hardpoint-to-Object transform. + * + * Note in the general case, it is not safe to look up an index for + * a hardpoint and then use the index. For skeletal appearances, indices + * change when wearables are applied. Name lookup is a must when + * possibly dealing with skeletal appearances. + * + * @param hardpointName the name of the hardpoint to look up. + * @param hardpointTransform the result is returned in this parameter + * upon successful completion. + * + * @return true if the hardpoint with the given name was found; false + * otherwise. + */ + +bool Appearance::findHardpoint(CrcString const &hardpointName, Transform &hardpointTransform) const +{ + // There are no hardpoints if there is no appearance template. + if (!m_appearanceTemplate) + return false; + + //-- The default implementation is to lookup the hardpoint via the appearance template. + const int hardpointIndex = getHardpointIndex(hardpointName, true); + if (hardpointIndex < 0) + return false; + else + { + //-- Handle the appearance scale. + Transform scaleTransform(Transform::IF_none); + scaleTransform.setToScale(m_scale); + + //-- Get the hardpoint transform from the hardpoint object. + const Hardpoint &hardpoint = getHardpoint(hardpointIndex); + hardpointTransform.multiply(scaleTransform, hardpoint.getTransform()); + + return true; + } +} + +// ---------------------------------------------------------------------- +/** + * Notify this Appearance of a change in scale. + * + * Implementers of derived classes should chain down to this function to + * ensure that the internal scale variable is set. + * + * @param scale the new scale factor, where a scale of (1,1,1) is equivalent to not scaling. + */ + +void Appearance::setScale(const Vector &scale) +{ + Vector const oldValue = m_scale; + m_scale = scale; + + onScaleModified(oldValue, m_scale); +} + +// ---------------------------------------------------------------------- + +const char * Appearance::getAppearanceTemplateName () const +{ + if (m_appearanceTemplate) + return m_appearanceTemplate->getName (); + else + return 0; +} + +// ---------------------------------------------------------------------- + +DPVS::Object *Appearance::getDpvsObject() const +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +bool Appearance::debugRenderingEnabled() const +{ + return true; +} + +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void Appearance::drawDebugShapes(DebugShapeRenderer * renderer) const +{ + if (renderer && debugRenderingEnabled()) + { + if(m_appearanceTemplate) + m_appearanceTemplate->drawDebugShapes(renderer); + + if (ms_drawAppearanceFrames) + renderer->drawFrame(1.0f); + + const Object *owner = getOwner(); + if (owner) + { + CollisionProperty const * collision = owner->getCollisionProperty(); + if(collision) + collision->drawDebugShapes(renderer); + + Object const * parent = owner->getParent(); + if (parent) + { + CellProperty const * cellProperty = parent->getCellProperty(); + if (cellProperty) + cellProperty->drawDebugShapes(renderer); + } + } + } +} + +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +int Appearance::getPolygonCount () const +{ + return 0; +} + +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void Appearance::debugDump(std::string & /*result*/, const int /*indentLevel*/) const +{ +} + +#endif + +// ---------------------------------------------------------------------- + +const IndexedTriangleList* Appearance::getRadarShape () const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +bool Appearance::getShadowBlobAllowed() const +{ + return m_shadowBlobAllowed; +} + +// ---------------------------------------------------------------------- + +void Appearance::setShadowBlobAllowed() +{ + m_shadowBlobAllowed = true; +} + +// ---------------------------------------------------------------------- + +void Appearance::renderShadowBlob (const Vector& /*position_o*/, const float /*radius*/) const +{ +} + +// ---------------------------------------------------------------------- + +void Appearance::renderReticle (const Vector& /*position_o*/, const float /*radius*/) const +{ +} + +// ---------------------------------------------------------------------- + +void Appearance::setRenderedThisFrame () const +{ + m_renderedFrameNumber = ms_frameNumber; +} + +// ---------------------------------------------------------------------- + +bool Appearance::getRenderedThisFrame () const +{ + return m_renderedFrameNumber == ms_frameNumber; +} + +//---------------------------------------------------------------------- + +bool Appearance::getRenderedLastFrame () const +{ + return m_renderedFrameNumber == (ms_frameNumber - 1); +} + +// ---------------------------------------------------------------------- + +SkeletalAppearance2 * Appearance::asSkeletalAppearance2() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +SkeletalAppearance2 const * Appearance::asSkeletalAppearance2() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +ComponentAppearance * Appearance::asComponentAppearance() +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +ComponentAppearance const * Appearance::asComponentAppearance() const +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +DetailAppearance * Appearance::asDetailAppearance() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +DetailAppearance const * Appearance::asDetailAppearance() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +void Appearance::onEvent(LabelHash::Id /* eventId */) +{ + // Default: handle no events. +} + +// ---------------------------------------------------------------------- + +int Appearance::getHardpointCount() const +{ + return m_appearanceTemplate != NULL ? m_appearanceTemplate->getHardpointCount() : 0; +} + +// ---------------------------------------------------------------------- + +int Appearance::getHardpointIndex(CrcString const &hardpointName, bool optional) const +{ + return m_appearanceTemplate != NULL ? m_appearanceTemplate->getHardpointIndex(hardpointName, optional) : -1; +} + +// ---------------------------------------------------------------------- + +const Hardpoint & Appearance::getHardpoint(int index) const +{ + NOT_NULL(m_appearanceTemplate); + return m_appearanceTemplate->getHardpoint(index); +} + +// ====================================================================== +// class Appearance: PROTECTED +// ====================================================================== + +void Appearance::extentChanged() const +{ + const Object *owner = getOwner(); + if (owner) + { + const_cast(owner)->extentChanged(); + } +} + +// ---------------------------------------------------------------------- + +void Appearance::onScaleModified(Vector const &oldScale, Vector const &newScale) +{ + // Do nothing. + UNREF(oldScale); + UNREF(newScale); +} + +// ---------------------------------------------------------------------- + +bool Appearance::canRenderEffects() +{ + return s_renderEnabled; +} + +// ---------------------------------------------------------------------- + +void Appearance::enableRenderEffects(bool const yesno) +{ + s_renderEnabled = yesno; +} + +// ---------------------------------------------------------------------- + +void Appearance::useRenderEffectsFlag(bool const yesno) +{ + m_useRenderEffectsFlag = yesno; +} + +// ---------------------------------------------------------------------- + +bool Appearance::usesRenderEffectsFlag() const +{ + return m_useRenderEffectsFlag; +} + +// ---------------------------------------------------------------------- + +ParticleEffectAppearance * Appearance::asParticleEffectAppearance() +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +ParticleEffectAppearance const * Appearance::asParticleEffectAppearance() const +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +SwooshAppearance * Appearance::asSwooshAppearance() +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +SwooshAppearance const * Appearance::asSwooshAppearance() const +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +LightningAppearance * Appearance::asLightningAppearance() +{ + return NULL; +} + +// ---------------------------------------------------------------------- + +LightningAppearance const * Appearance::asLightningAppearance() const +{ + return NULL; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Appearance.h b/engine/shared/library/sharedObject/src/shared/appearance/Appearance.h new file mode 100644 index 00000000..13b49530 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Appearance.h @@ -0,0 +1,273 @@ +// ====================================================================== +// +// Appearance.h +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001, 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Appearance_H +#define INCLUDED_Appearance_H + +// ====================================================================== + +#include "sharedFoundation/LabelHash.h" +#include "sharedFoundation/Tag.h" +#include "sharedMath/Vector.h" +#include "sharedMath/Transform.h" + +class AppearanceTemplate; +class AxialBox; +class BoxExtent; +class CollideParameters; +class CollisionInfo; +class ComponentAppearance; +class CrcLowerString; +class CrcString; +class CustomizationData; +class DebugShapeRenderer; +class DetailAppearance; +class Extent; +class Hardpoint; +class IndexedTriangleList; +class LightningAppearance; +class LightsaberAppearance; +class Object; +class ParticleEffectAppearance; +class SkeletalAppearance2; +class Sphere; +class SwooshAppearance; +class Texture; +class Vector; +typedef uint32 PropertyId; + +namespace DPVS +{ + class Object; +}; + +// ====================================================================== + +class Appearance +{ + // {Detail,Component,Lightsaber}Appearance need access to Appearance::getDpvsObject() + friend class DetailAppearance; + friend class ComponentAppearance; + friend class LightsaberAppearance; + +public: + + static void install(); + + static void beginNewFrame (); + + typedef void (*RenderHardpointFunction)(Transform const & transform_h2w, bool renderName, char const * name); + static void setRenderHardpointFunction(RenderHardpointFunction renderHardpointFunction); + + static bool canRenderEffects(); + static void enableRenderEffects(bool yesno); + + void useRenderEffectsFlag(bool yesno); + bool usesRenderEffectsFlag() const; + +public: + + explicit Appearance(const AppearanceTemplate *newAppearanceTemplate); + virtual ~Appearance(); + + const AppearanceTemplate *getAppearanceTemplate() const; + const char * getAppearanceTemplateName () const; + + virtual bool isLoaded() const; + + virtual const Sphere &getSphere() const; + + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + virtual bool implementsCollide() const; + + virtual const Extent *getSelectionExtent() const; + virtual const Extent *getExtent() const; + virtual void setExtent(const Extent *newExent); + virtual AxialBox const getTangibleExtent() const; + + virtual float alter(float time); + + virtual void setAlpha(bool opaqueEnabled, float opaqueAlpha, bool alphaEnabled, float alphaAlpha); + + Object *getOwner(); + const Object *getOwner() const; + virtual void setOwner(Object *newOwner); + + void setTransform_w(const Transform &t) const; + const Transform & getTransform_w() const; + + const char *getFloorName() const; + + virtual void setCustomizationData(CustomizationData *customizationData); + virtual void addCustomizationVariables(CustomizationData &customizationData) const; + + virtual void setKeepAlive(bool keepAlive); + bool isAlive() const; + + virtual bool findHardpoint(CrcString const &hardpointName, Transform &hardpointTransform) const; + virtual int getHardpointCount() const; + virtual int getHardpointIndex(CrcString const &hardpointName, bool optional = false) const; + virtual const Hardpoint& getHardpoint(int index) const; + + virtual void setScale(Vector const & scale); + virtual Vector const & getScale() const; + void setUniformScale(float scale); + float getUniformScale() const; + + virtual void addToWorld(); + virtual void removeFromWorld(); + virtual void preRender() const; + virtual void render() const; + virtual void objectListCameraRender() const; + static void objectListCameraRenderDescend(Object const & obj); + + virtual void setTexture(Tag tag, const Texture &texture); + bool getShadowBlobAllowed() const; + virtual void setShadowBlobAllowed(); + virtual void renderShadowBlob (const Vector& position_o, float radius) const; + virtual void renderReticle (const Vector& position_o, float radius) const; + +#ifdef _DEBUG + virtual bool debugRenderingEnabled() const; + virtual void drawDebugShapes ( DebugShapeRenderer * R ) const; + virtual int getPolygonCount () const; + virtual void debugDump(std::string &result, int indentLevel) const; +#endif + + virtual const IndexedTriangleList* getRadarShape () const; + + void setRenderedThisFrame () const; + bool getRenderedThisFrame () const; + bool getRenderedLastFrame () const; + int getRenderedFrameNumber() const; + + virtual SkeletalAppearance2 * asSkeletalAppearance2(); + virtual SkeletalAppearance2 const * asSkeletalAppearance2() const; + + virtual ComponentAppearance * asComponentAppearance(); + virtual ComponentAppearance const * asComponentAppearance() const; + + virtual DetailAppearance * asDetailAppearance(); + virtual DetailAppearance const * asDetailAppearance() const; + + virtual ParticleEffectAppearance * asParticleEffectAppearance(); + virtual ParticleEffectAppearance const * asParticleEffectAppearance() const; + + virtual SwooshAppearance * asSwooshAppearance(); + virtual SwooshAppearance const * asSwooshAppearance() const; + + virtual LightningAppearance * asLightningAppearance(); + virtual LightningAppearance const * asLightningAppearance() const; + + virtual void onEvent(LabelHash::Id eventId); + +protected: + + void extentChanged() const; + + virtual bool realIsAlive() const; + virtual void onScaleModified(Vector const &oldScale, Vector const &newScale); + +private: + + // disabled + Appearance(); + Appearance(const Appearance &); + Appearance &operator =(const Appearance &); + + virtual DPVS::Object *getDpvsObject() const; + + /////////////////////////////////////////////////////////// + + const AppearanceTemplate *m_appearanceTemplate; + +protected: + + const Extent *m_extent; + +private: + + Object *m_owner; + mutable int m_renderedFrameNumber; + Vector m_scale; + bool m_keepAlive; + bool m_useRenderEffectsFlag; + bool m_shadowBlobAllowed; + mutable Transform m_appearanceToWorld; +}; + +// ====================================================================== +/** + * Get the AppearanceTemplate for this Appearance. + * + * The AppearanceTemplate may be NULL. + * + * AppearanceTemplates may be shared by multiple Appearances. + * + * @return const pointer to the AppearanceTemplate. + */ + +inline const AppearanceTemplate *Appearance::getAppearanceTemplate() const +{ + return m_appearanceTemplate; +} + +// ---------------------------------------------------------------------- + +inline Object *Appearance::getOwner() +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline const Object *Appearance::getOwner() const +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline const Transform &Appearance::getTransform_w() const +{ + return m_appearanceToWorld; +} + +// ---------------------------------------------------------------------- + +inline Vector const &Appearance::getScale() const +{ + return m_scale; +} + +// --------------------------------------------------------------------- + +inline void Appearance::setUniformScale(float const scale) +{ + setScale(Vector(scale, scale, scale)); +} + +// --------------------------------------------------------------------- + +inline float Appearance::getUniformScale() const +{ + // When requesting a uniform scale, the x-axis is the only one considered. + return getScale().x; +} + +// --------------------------------------------------------------------- + +inline int Appearance::getRenderedFrameNumber() const +{ + return m_renderedFrameNumber; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.cpp b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.cpp new file mode 100644 index 00000000..89f44831 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.cpp @@ -0,0 +1,494 @@ +// ====================================================================== +// +// AppearanceTemplate.cpp +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001-2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/AppearanceTemplate.h" + +#include "sharedCollision/ConfigSharedCollision.h" +#include "sharedCollision/ExtentList.h" +#include "sharedCollision/Extent.h" +#include "sharedDebug/DataLint.h" +#include "sharedCollision/FloorManager.h" +#include "sharedCollision/FloorMesh.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/Hardpoint.h" +#include "sharedFile/Iff.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/DataResourceList.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedMath/Transform.h" + +#include +#include +#include + +//----------------------------------------------------------------- + +namespace AppearanceTemplateNamespace +{ + const Tag TAG_APPR = TAG (A,P,P,R); + const Tag TAG_HPTS = TAG (H,P,T,S); + const Tag TAG_HPNT = TAG (H,P,N,T); + const Tag TAG_FLOR = TAG (F,L,O,R); + + bool ms_verboseWarnings; + + char ms_crashReportInfo[MAX_PATH * 2]; + + void remove(); +} + +using namespace AppearanceTemplateNamespace; + +// ====================================================================== +// PRIVATE AppearanceTemplate::PreloadManager +// ====================================================================== + +class AppearanceTemplate::PreloadManager +{ +public: + + explicit PreloadManager (const AppearanceTemplate* appearanceTemplate); + ~PreloadManager (); + +private: + + PreloadManager (); + PreloadManager (const PreloadManager&); + PreloadManager& operator= (const PreloadManager&); + +private: + + const FloorMesh* m_preloadFloorMesh; +}; + +// ---------------------------------------------------------------------- + +AppearanceTemplate::PreloadManager::PreloadManager (const AppearanceTemplate* const appearanceTemplate) : + m_preloadFloorMesh (0) +{ + if (appearanceTemplate->m_floorName) + m_preloadFloorMesh = FloorMeshList::fetch (appearanceTemplate->m_floorName); +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate::PreloadManager::~PreloadManager () +{ + if (m_preloadFloorMesh) + { + m_preloadFloorMesh->releaseReference (); + m_preloadFloorMesh = 0; + } +} + +// ====================================================================== +// Construct an AppearanceTemplate + +AppearanceTemplate::AppearanceTemplate(const char *newName) +: m_referenceCount(0), + m_crcName(new CrcLowerString(newName)), + m_extent(NULL), + m_collisionExtent(NULL), + m_hardpoints(NULL), + m_floorName(NULL), + m_preloadManager (0) +{ + //-- Save info on most recently constructed appearance template. + IGNORE_RETURN(snprintf(ms_crashReportInfo, sizeof(ms_crashReportInfo) - 1, "AppearanceTemplate: %s\n", newName ? newName : "")); + ms_crashReportInfo[sizeof(ms_crashReportInfo) - 1] = '\0'; +} + +// ---------------------------------------------------------------------- +/** + * Destroy an AppearanceTemplate. + */ + +AppearanceTemplate::~AppearanceTemplate(void) +{ + delete m_crcName; + + ExtentList::release(m_extent); + m_extent = NULL; + + ExtentList::release(m_collisionExtent); + m_collisionExtent = NULL; + + if (m_hardpoints) + { + std::for_each(m_hardpoints->begin(), m_hardpoints->end(), PointerDeleter()); + delete m_hardpoints; + m_hardpoints = 0; + } + + delete [] m_floorName; + + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::install() +{ + AppearanceTemplateList::assignBinding(TAG_APPR, create); + + ms_crashReportInfo[0] = '\0'; + CrashReportInformation::addDynamicText(ms_crashReportInfo); + + ExitChain::add(remove, "AppearanceTemplateList::remove"); +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateNamespace::remove() +{ + AppearanceTemplateList::removeBinding(TAG_APPR); + CrashReportInformation::removeDynamicText(ms_crashReportInfo); +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate *AppearanceTemplate::create(const char *newName, Iff *iff) +{ + AppearanceTemplate * temp = new AppearanceTemplate(newName); + temp->load(*iff); + return temp; +} + +// ---------------------------------------------------------------------- +/** + * Create a unique Appearance for this AppearanceTemplate. + * + * This routine should be overloaded in derived classes as appropriate. + * + * Derived classes should not chain down to this routine. + * + * @return An Appearance for the specified AppearanceTemplate + */ + +Appearance *AppearanceTemplate::createAppearance() const +{ + return new Appearance(this); +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::load(Iff & iff) +{ + iff.enterForm(TAG_APPR); + +#ifdef _DEBUG + DEBUG_WARNING (DataLint::isEnabled () && iff.getCurrentName () < TAG_0003, ("AppearanceTemplate [%s] loading older version -- this asset will need to be reexported", getCrcName ().getString ())); +#endif + + switch (iff.getCurrentName()) + { + case TAG_0001: + load_0001(iff); + break; + + case TAG_0002: + load_0002(iff); + break; + + case TAG_0003: + load_0003(iff); + break; + + default: + FATAL (true, ("AppearanceTemplate::load - unsupported format")); + break; + } + + iff.exitForm(TAG_APPR); +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::load_0001(Iff &iff) +{ + iff.enterForm(TAG_0001); + + loadExtents(iff); + loadHardpoints(iff); + + iff.exitForm(TAG_0001); +} + +// ---------- + +void AppearanceTemplate::load_0002(Iff &iff) +{ + iff.enterForm(TAG_0002); + + loadExtents(iff); + loadHardpoints(iff); + IGNORE_RETURN(loadFloors(iff)); + + iff.exitForm(TAG_0002); +} + +// ---------- + +void AppearanceTemplate::load_0003(Iff & iff) +{ + iff.enterForm(TAG_0003); + + loadExtents(iff); + loadCollisionExtents(iff); + loadHardpoints(iff); + IGNORE_RETURN(loadFloors(iff)); + + iff.exitForm(TAG_0003); +} + +// ---------------------------------------------------------------------- +/** + * Load the extents out of an Iff. + * + * @param iff Iff containing the extent information + */ + +void AppearanceTemplate::loadExtents (Iff & iff) +{ + m_extent = ExtentList::fetch(iff); +} + +void AppearanceTemplate::loadCollisionExtents (Iff & iff) +{ + m_collisionExtent = ExtentList::fetch(iff); + + if(m_collisionExtent && !m_collisionExtent->validate()) + { + DEBUG_WARNING(true,("AppearanceTemplate::loadCollisionExtents - Extent loaded from %s is invalid",iff.getFileName())); + } +} + +// ---------------------------------------------------------------------- +/** + * Load the hardpoints out of an Iff. + */ + +void AppearanceTemplate::loadHardpoints (Iff& iff) +{ + // This enterForm call MUST be optional, as older versions of the exporter + // just didn't write out this form if there weren't any hardpoints + // (instead of writing an empty form) + + if(iff.enterForm(TAG_HPTS,true)) + { + char hardpointName[256]; + Transform hardpointTransform; + + int nHardpoints = iff.getNumberOfBlocksLeft(); + + if (m_hardpoints) + { + std::for_each(m_hardpoints->begin(), m_hardpoints->end(), PointerDeleter()); + m_hardpoints->clear(); + } + else + { + m_hardpoints = new HardpointList(); + m_hardpoints->reserve(static_cast(nHardpoints)); + } + + for (int i = 0; i < nHardpoints; ++i) + { + iff.enterChunk(TAG_HPNT); + hardpointTransform = iff.read_floatTransform(); + iff.readRest_char(hardpointName, sizeof(hardpointName)); + iff.exitChunk(TAG_HPNT); + + m_hardpoints->push_back(new Hardpoint (hardpointName, hardpointTransform)); + } + + iff.exitForm(TAG_HPTS); + + //-- Sort the hardpoints by crc name. + std::sort(m_hardpoints->begin(), m_hardpoints->end(), Hardpoint::LessNameComparator()); + } +} + +// ---------------------------------------------------------------------- + +bool AppearanceTemplate::loadFloors( Iff & iff ) +{ + iff.enterForm (TAG_FLOR); + + iff.enterChunk(TAG_DATA); + + bool hasFloor = iff.read_bool8(); + if(hasFloor) + m_floorName = iff.read_string(); + + iff.exitChunk(TAG_DATA); + + iff.exitForm(TAG_FLOR); + + return true; +} + +//------------------------------------------------------------------- + +char const * AppearanceTemplate::getFloorName() const +{ + return m_floorName; +} + +// ---------------------------------------------------------------------- +/** + * Set a new Extent for this AppearanceTemplate. + * + * The current extent will be released. + * + * @param newExtent New extent for this AppearanceTemplate + */ + +void AppearanceTemplate::setExtent(const Extent *newExtent) +{ + ExtentList::release(m_extent); + m_extent = newExtent; +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::setCollisionExtent ( Extent const * newExtent ) +{ + ExtentList::release(m_collisionExtent); + m_collisionExtent = newExtent; +} + +// ---------------------------------------------------------------------- +/** + * retrieve the index of a hardpoint given the hardpoint name. + * + * Hardpoint names are compared in a case-insensitive manner. + * + * The argument "optional" controls activity when the hardpoint name is not + * found. The routine will FATAL if optional is false and the hardpoint name + * is not found. The routine will return -1 if optional is true and the + * hardpoint name isn't found. + * + * @return index of hardpoint with given name if found, -1 or FATAL otherwise (see remarks). + */ + +int AppearanceTemplate::getHardpointIndex(CrcString const &hardpointName, bool optional) const +{ + //-- Handle no-hardpoint case. + if (!m_hardpoints) + { + FATAL(!optional, ("getHardpointIndex(%s) called non-optionally on appearance template [%s] with no hardpoints.", hardpointName.getString(), m_crcName->getString())); + return -1; + } + + //-- Search for the hardpoint in Crc order. + std::pair const rangePair = std::equal_range(m_hardpoints->begin(), m_hardpoints->end(), hardpointName, Hardpoint::LessNameComparator()); + if (rangePair.first == rangePair.second) + { + FATAL(!optional, ("getHardpointIndex(%s) called non-optionally on appearance template [%s], hardpoint doesn't exist.", hardpointName.getString(), m_crcName->getString())); + return -1; + } + + return std::distance(m_hardpoints->begin(), rangePair.first); +} + +//------------------------------------------------------------------- + +const Hardpoint& AppearanceTemplate::getHardpoint(int index) const +{ + NOT_NULL(m_hardpoints); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getHardpointCount()); + + return *((*m_hardpoints)[static_cast(index)]); +} + +// ---------------------------------------------------------------------- + +int AppearanceTemplate::getHardpointCount(void) const +{ + return m_hardpoints ? static_cast(m_hardpoints->size()) : 0; +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::drawDebugShapes ( DebugShapeRenderer * renderer ) const +{ + UNREF(renderer); + +#ifdef _DEBUG + + if(ConfigSharedCollision::getDrawExtents()) + { + if(m_collisionExtent) + { + m_collisionExtent->drawDebugShapes(renderer); + } + } + +#endif +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::preloadAssets() const +{ + if (!m_preloadManager) + m_preloadManager = new PreloadManager (this); +} + + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::preloadAssetsLight () const +{ +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplate::garbageCollect() const +{ + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } +} + +// ---------------------------------------------------------------------- +/** + *Get the CrcLowerString for this AppearanceTemplate. + */ + +const CrcLowerString &AppearanceTemplate::getCrcName() const +{ + return *m_crcName; +} + +// ---------------------------------------------------------------------- +/** + *Get the name of this AppearanceTemplate. + * + *This routine may return NULL. + */ + +const char *AppearanceTemplate::getName() const +{ + return m_crcName->getString(); +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.h b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.h new file mode 100644 index 00000000..b3e4d3f1 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplate.h @@ -0,0 +1,153 @@ +// ====================================================================== +// +// AppearanceTemplate.h +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_AppearanceTemplate_H +#define INCLUDED_AppearanceTemplate_H + +// ====================================================================== + +class Appearance; +class Camera; +class CrcLowerString; +class CrcString; +class Extent; +class Hardpoint; +class Iff; +class Object; +class Sphere; +class Vector; +class DebugShapeRenderer; + +// ====================================================================== + +class AppearanceTemplate +{ +public: + + static void install(); + + static AppearanceTemplate *create(const char *newName, Iff *iff); + +public: + + explicit AppearanceTemplate(const char *newName); + virtual ~AppearanceTemplate(); + + virtual Appearance *createAppearance() const; + virtual void drawDebugShapes(DebugShapeRenderer *renderer) const; + + virtual void preloadAssets () const; + //-- we use this function to do some preloading but nothing big. Characters use it in preloading since loading all .MGNs as done by preloadAssets() generally is too heavy. + virtual void preloadAssetsLight () const; + virtual void garbageCollect () const; + + const CrcLowerString &getCrcName() const; + const char *getName() const; + + const Extent *getExtent() const; + void setExtent(const Extent *newExent); + + const Extent *getCollisionExtent() const; + void setCollisionExtent(Extent const *newExtent); + + + int getHardpointCount() const; + int getHardpointIndex(CrcString const &hardpointName, bool optional = false) const; + const Hardpoint& getHardpoint(int index) const; + + const char *getFloorName() const; + + int getReferenceCount() const; + int incrementReference() const; + int decrementReference() const; + + void load(Iff &iff); + +protected: + + void load_0001(Iff &iff); + void load_0002(Iff &iff); + void load_0003(Iff &iff); + + void loadExtents(Iff &iff); + void loadCollisionExtents(Iff &iff); + void loadHardpoints(Iff &iff); + + bool loadFloors(Iff &iff); + +private: + + typedef stdvector::fwd HardpointList; + +private: + + AppearanceTemplate(); + AppearanceTemplate(const AppearanceTemplate &); + AppearanceTemplate &operator =(const AppearanceTemplate &); + +private: + + mutable int m_referenceCount; + CrcLowerString *const m_crcName; + const Extent *m_extent; + + const Extent *m_collisionExtent; + + HardpointList *m_hardpoints; + + char * m_floorName; + + class PreloadManager; + friend class PreloadManager; + mutable PreloadManager* m_preloadManager; +}; + +// ---------------------------------------------------------------------- +/** + *Return the Extent for this AppearanceTemplate. + */ + +inline const Extent *AppearanceTemplate::getExtent() const +{ + return m_extent; +} + +inline const Extent *AppearanceTemplate::getCollisionExtent() const +{ + return m_collisionExtent; +} + +// ---------------------------------------------------------------------- + +inline int AppearanceTemplate::getReferenceCount() const +{ + return m_referenceCount; +} + +// ---------- + +inline int AppearanceTemplate::incrementReference() const +{ + m_referenceCount++; + + return m_referenceCount; +} + +// ---------- + +inline int AppearanceTemplate::decrementReference() const +{ + m_referenceCount--; + + return m_referenceCount; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.cpp b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.cpp new file mode 100644 index 00000000..b0885c86 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.cpp @@ -0,0 +1,736 @@ +// ====================================================================== +// +// AppearanceTemplateList.cpp +// copyright 1999 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/AppearanceTemplateList.h" + +#include "sharedDebug/DataLint.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedFoundation/PersistentCrcString.h" +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedFile/AsynchronousLoader.h" +#include "sharedFile/Iff.h" +#include "sharedFile/TreeFile.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedRandom/Random.h" + +#include +#include +#include +#include + +// ====================================================================== +// AppearanceTemplateListNamespace +// ====================================================================== + +namespace AppearanceTemplateListNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::map TagBindingMap; + typedef std::map RedirectorMap; + typedef std::set AnonymousTemplates; + typedef std::map NamedTemplates; + typedef std::pair TimedTemplate; + typedef std::map NamedTimedTemplates; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + const Tag TAG_APT = TAG3(A,P,T); + const Tag TAG_MESH = TAG(M,E,S,H); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + const char* const ms_defaultAppearanceTemplateName = "appearance/defaultappearance.apt"; + float ms_keepTime; + float ms_keepEpsilon; + bool ms_installed; + bool ms_debugReport; + bool ms_debugReportVerbose; + bool ms_debugReportTimedTemplates; + TagBindingMap ms_tagBindingMap; + RedirectorMap ms_redirectorMap; + AnonymousTemplates ms_anonymousTemplates; + NamedTemplates ms_namedTemplates; + NamedTimedTemplates ms_namedTimedTemplates; + bool ms_allowTimedTemplates; + bool ms_useTimedTemplates; + bool ms_logCreate; + bool ms_logFetch; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void remove(); + AppearanceTemplate *create(const char *fileName); + void addAnonymousAppearanceTemplate(AppearanceTemplate *appearanceTemplate); + void addNamedAppearanceTemplate(AppearanceTemplate *appearanceTemplate); + void addNamedTimedAppearanceTemplate(AppearanceTemplate *appearanceTemplate); + void removeAppearanceTemplate(AppearanceTemplate *appearanceTemplate); + void debugReport(); + void debugReportVerbose(); + void debugReportTimedTemplates(); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace AppearanceTemplateListNamespace; + +// ====================================================================== +// STATIC PUBLIC AppearanceTemplateList +// ====================================================================== + +/** + * Install the AppearanceTemplateList. + */ +void AppearanceTemplateList::install(bool useTimedTemplates, bool ensureDefaultAppearanceExists) +{ + DEBUG_FATAL(ms_installed, ("double install")); + ms_installed = true; + + DebugFlags::registerFlag(ms_debugReport, "SharedObject/AppearanceTemplateList", "debugReport", debugReport); + DebugFlags::registerFlag(ms_debugReportTimedTemplates, "SharedObject/AppearanceTemplateList", "reportTimedTemplates", debugReportTimedTemplates); + DebugFlags::registerFlag(ms_debugReportVerbose, "SharedObject/AppearanceTemplateList", "debugReportVerbose", debugReportVerbose); + DebugFlags::registerFlag(ms_useTimedTemplates, "SharedObject/AppearanceTemplateList", "useTimedTemplates"); + DebugFlags::registerFlag(ms_logCreate, "SharedObject/AppearanceTemplateList", "logCreate"); + DebugFlags::registerFlag(ms_logFetch, "SharedObject/AppearanceTemplateList", "logFetch"); + + ms_useTimedTemplates = useTimedTemplates; + ms_keepTime = ConfigSharedObject::getAppearanceTemplateListKeepTime(); + ms_keepEpsilon = ConfigSharedObject::getAppearanceTemplateListKeepEpsilon(); + + //-- verify the default appearance exists + if (ensureDefaultAppearanceExists) + FATAL(!TreeFile::exists(getDefaultAppearanceTemplateName()), ("%s could not be found. Are your paths set up correctly?", getDefaultAppearanceTemplateName())); + + if (TreeFile::isLoggingFiles()) + delete TreeFile::open(getDefaultAppearanceTemplateName(), AbstractFile::PriorityData, true); + + ExitChain::add(AppearanceTemplateListNamespace::remove, "AppearanceTemplateList::remove", 0, false); +} + +// ---------------------------------------------------------------------- +/** + * Assign a binding between a Tag and a CreateFunction. + * + * If a previous binding for the specified tag exists, it will be replaced + * by the new binding. + * + * @param tag Tag for the binding + * @param createFunction Create function to call for data files with the tag + */ + +void AppearanceTemplateList::assignBinding(const Tag tag, const CreateFunction createFunction) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + NOT_NULL(createFunction); + +#ifdef _DEBUG + char tagString[5]; + ConvertTagToString(tag, tagString); + DEBUG_REPORT_LOG_PRINT(ms_debugReport, ("Added AppearanceTemplateList binding %s\n", tagString)); +#endif + + ms_tagBindingMap[tag] = createFunction; +} + +// ---------------------------------------------------------------------- +/** + * Remove a binding from the AppearanceTemplateList. + * + * If the specified Tag is not bound, the routine will return without + * error. + * + * @param tag Tag for the binding to remove + */ + +void AppearanceTemplateList::removeBinding(const Tag tag) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + + IGNORE_RETURN(ms_tagBindingMap.erase(tag)); +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateList::update(const float elapsedTime) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + + //-- walk the timed appearance template list and tick down + NamedTimedTemplates::iterator iter = ms_namedTimedTemplates.begin(); + NamedTimedTemplates::iterator end = ms_namedTimedTemplates.end(); + + while (iter != end) + { + //-- see if the appearance template has expired + iter->second.first -= elapsedTime; + if (iter->second.first <= 0.f) + { + DEBUG_REPORT_LOG(ms_logCreate, ("Destroying timed appearance %s\n", iter->first->getString())); + delete const_cast(iter->second.second); + + ms_namedTimedTemplates.erase(iter++); + end = ms_namedTimedTemplates.end(); + } + else + ++iter; + } +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateList::setAllowTimedTemplates(const bool allowTimedTemplates) +{ + ms_allowTimedTemplates = allowTimedTemplates; + + if (!ms_allowTimedTemplates) + update(ms_keepTime + ms_keepEpsilon); +} + +// ---------------------------------------------------------------------- + +const AppearanceTemplate *AppearanceTemplateList::fetch(const char *const fileName) +{ + bool found = false; + return fetch(fileName, found); +} + +//---------------------------------------------------------------------- + +const AppearanceTemplate *AppearanceTemplateList::fetch(const char *const fileName, bool & found) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + NOT_NULL(fileName); + + DEBUG_REPORT_LOG(ms_logFetch, ("[fetch] AppearanceTemplateList::fetch: %s\n", fileName)); + + found = false; + char const * actualFileName = fileName; + if (!fileName) + { + DEBUG_WARNING(true, ("AppearanceTemplateList::fetch passed NULL fileName, using default")); + actualFileName = getDefaultAppearanceTemplateName(); + } + else if (!*fileName) + { + DEBUG_WARNING(true, ("AppearanceTemplateList::fetch passed empty fileName, using default")); + actualFileName = getDefaultAppearanceTemplateName(); + } + else if (!TreeFile::exists(fileName)) + { + DEBUG_WARNING(true, ("AppearanceTemplateList::fetch could not open '%s', using default", fileName)); + actualFileName = getDefaultAppearanceTemplateName(); + } + else + found = true; + + //-- search for the appearance + AppearanceTemplate *const appearanceTemplate = create(actualFileName); + + //-- up the reference count + return fetch(appearanceTemplate); +} + +// ---------------------------------------------------------------------- +/** + * Add a reference to the specified Appearance. + * + * This routine will do nothing if passed in NULL. Otherwise, it will + * increase the reference count of the specified AppearanceTemplate + * by one. + * + * @param appearanceTemplate AppearanceTemplate to remove the reference count from + * @return The AppearanceTemplate that was passed into the routine. + * @see AppearanceTemplateList::release() + */ + +const AppearanceTemplate *AppearanceTemplateList::fetch(const AppearanceTemplate *const appearanceTemplate) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + if (appearanceTemplate) + IGNORE_RETURN(appearanceTemplate->incrementReference()); + + return appearanceTemplate; +} + +// ---------------------------------------------------------------------- +/** + * Fetch an AppearanceTemplate from an Iff. + * + * This routine will increment the reference count of the AppearanceTemplate + * by one. + * + * @param iff File from which to load the AppearanceTemplate + */ + +const AppearanceTemplate *AppearanceTemplateList::fetch(Iff *const iff) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + NOT_NULL(iff); + + const Tag tag = iff->getCurrentName(); + + TagBindingMap::iterator iter = ms_tagBindingMap.find(tag); + if (iter == ms_tagBindingMap.end()) + { + char tagString[5]; + ConvertTagToString(tag, tagString); + DEBUG_FATAL(true, ("AppearanceTemplate binding %s not found", tagString)); + return 0; //lint !e527 // unreachable + } + + AppearanceTemplate *const appearanceTemplate = (*iter).second(NULL, iff); + NOT_NULL(appearanceTemplate); + + addAnonymousAppearanceTemplate(appearanceTemplate); + + //-- up the reference count + return fetch(appearanceTemplate); +} + +// ---------------------------------------------------------------------- +/** + * Fetch an AppearanceTemplate from an existing object and add the object + * to the AppearanceTemplateList. + * + * The AppearanceTemplate object is assumed to be created outside the + * AppearanceTemplateList fetch-from-file or fetch-from-iff mechanism. + * This may happen within an editor that creates an AppearanceTemplate + * object from scratch. In this case, the object is created outside + * the AppearanceTemplateList and must be added to the list. Use this + * function to do so. Failure to add the object to this + * list likely will cause failures when an Appearance making use of the + * AppearanceTemplate object gets released. + * + * @param appearanceTemplate the AppearanceTemplate object to add to the AppearanceTemplateList + * + * @return the AppearanceTemplate object, returned just like all the other fetch routines + */ + +const AppearanceTemplate *AppearanceTemplateList::fetchNew(AppearanceTemplate *const appearanceTemplate) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + NOT_NULL(appearanceTemplate); + + const CrcLowerString &crcName = appearanceTemplate->getCrcName(); + const char *const crcString = crcName.getString(); + if (crcString && *crcString) + { + //-- we've got a named appearance template list + addNamedAppearanceTemplate(appearanceTemplate); + } + else + { + //-- we've got an anonymous appearance template list + addAnonymousAppearanceTemplate(appearanceTemplate); + } + + //-- up the reference count + return fetch(appearanceTemplate); +} + +// ---------------------------------------------------------------------- +/** + * Remove a reference to the specified AppearanceTemplate. + * + * This routine will do nothing if passed in NULL. + * + * If the reference count drops to 0, the AppearanceTemplate will be deleted. + * + * @param appearanceTemplate AppearanceTemplate to remove the reference count from + * @see AppearanceTemplateList::release() + */ + +void AppearanceTemplateList::release(const AppearanceTemplate *const appearanceTemplate) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + if (appearanceTemplate && appearanceTemplate->decrementReference() <= 0) + { + DEBUG_FATAL(appearanceTemplate->getReferenceCount() < 0, ("referenceCount is negative")); + + AppearanceTemplate *const nonConstAppearanceTemplate = const_cast(appearanceTemplate); + + //-- remove from list + removeAppearanceTemplate(nonConstAppearanceTemplate); + CrcLowerString const & crcName = appearanceTemplate->getCrcName(); + char const * const crcString = crcName.getString(); + + //-- add it to the timed template list + if (ms_useTimedTemplates && ms_allowTimedTemplates && crcString && *crcString) + { + DEBUG_REPORT_LOG(ms_logCreate, ("Adding timed appearance %s\n", appearanceTemplate->getName())); + addNamedTimedAppearanceTemplate(nonConstAppearanceTemplate); + } + else + delete nonConstAppearanceTemplate; + } +} + +// ---------------------------------------------------------------------- +/** + * Create an Appearance for the specified AppearanceTemplate. + * + * @param fileName Name of the AppearanceTemplate + * @return An appearance for the specified AppearanceTemplate + */ + +Appearance *AppearanceTemplateList::createAppearance(const char *const fileName) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + +#ifdef _DEBUG + DataLint::pushAsset(fileName); +#endif + + //-- get the appearance template + const AppearanceTemplate *const appearanceTemplate = fetch(fileName); + + //-- creating the appearance will increment the reference count + Appearance *const appearance = appearanceTemplate->createAppearance(); + +#ifdef _DEBUG + DataLint::popAsset(); +#endif // _DEBUG + + //-- release the appearance template, since the appearance now holds a ref count for it + release(appearanceTemplate); + + return appearance; +} + +// ---------------------------------------------------------------------- + +const char* AppearanceTemplateList::getDefaultAppearanceTemplateName() +{ + return ms_defaultAppearanceTemplateName; +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateList::garbageCollect () +{ + //-- release the timed (cached) appearance templates + if (ms_allowTimedTemplates) + { + setAllowTimedTemplates (false); + setAllowTimedTemplates (true); + } + + //-- call garbage collect on all appearance templates + { + NamedTemplates::iterator end = ms_namedTemplates.end (); + NamedTemplates::iterator iter = ms_namedTemplates.begin (); + for (; iter != end; ++iter) + const_cast (iter->second)->garbageCollect (); + } +} + +// ====================================================================== +// STATIC PRIVATE AppearanceTemplateList +// ====================================================================== + +/** + * Remove a AppearanceTemplateList. + */ +void AppearanceTemplateListNamespace::remove() +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + ms_installed = false; + + DebugFlags::unregisterFlag(ms_debugReport); + DebugFlags::unregisterFlag(ms_debugReportTimedTemplates); + DebugFlags::unregisterFlag(ms_debugReportVerbose); + DebugFlags::unregisterFlag(ms_useTimedTemplates); + DebugFlags::unregisterFlag(ms_logCreate); + DebugFlags::unregisterFlag(ms_logFetch); + + { + //-- report if we leaked anonymous appearance templates + const size_t entryCount = ms_anonymousTemplates.size(); + DEBUG_WARNING(entryCount, ("leaked %u anonymous appearance templates", entryCount)); + UNREF(entryCount); + // shouldn't delete because item may depend on items that are memory block managed and already deleted, which could cause a crash + } + + { + //-- report if we leaked named appearance templates +#ifdef _DEBUG + const size_t entryCount = ms_namedTemplates.size(); + DEBUG_WARNING(entryCount, ("leaked %u named appearance templates", entryCount)); + + NamedTemplates::iterator end = ms_namedTemplates.end(); + for (NamedTemplates::iterator it = ms_namedTemplates.begin(); it != end; ++it) + { + DEBUG_REPORT_LOG(true, ("--leaked [%s]\n", it->second->getCrcName().getString())); + // shouldn't delete because item may depend on items that are memory block managed and already deleted, which could cause a crash + } +#endif + } + + { +#ifdef _DEBUG + const size_t entryCount = ms_namedTimedTemplates.size(); + if (entryCount) + { + DEBUG_REPORT_LOG(true, ("%u timed appearance templates remain\n", entryCount)); + } +#endif + } + + { + DEBUG_REPORT_LOG(ms_debugReport, ("AppearanceTemplateList redirector map:\n")); + + //-- delete the redirector map + for (RedirectorMap::iterator iter = ms_redirectorMap.begin(); iter != ms_redirectorMap.end(); ++iter) + { + DEBUG_REPORT_LOG(ms_debugReport, (" %4i %s -> %s\n", std::distance(ms_redirectorMap.begin(), iter), iter->first->getString(), iter->second->getString())); + delete const_cast(iter->first); + delete const_cast(iter->second); + } + } +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate *AppearanceTemplateListNamespace::create(const char *const fileName) +{ + NOT_NULL(fileName); + + TemporaryCrcString actualFileName(fileName, true); + + //-- does the filename end in apt? + if (strstr(fileName, ".apt") != 0) + { + //-- is the filename in the redirector map? + RedirectorMap::iterator iter = ms_redirectorMap.find((const CrcString*)&actualFileName); + if (iter == ms_redirectorMap.end()) + { + //-- extract the real name from the apt + Iff iff(fileName); + iff.enterForm(TAG_APT); + iff.enterForm(TAG_0000); + iff.enterChunk(TAG_NAME); + + char redirectedFileName[Os::MAX_PATH_LENGTH]; + iff.read_string(redirectedFileName, Os::MAX_PATH_LENGTH); + + //-- make sure redirector name is not an apt file + FATAL(strstr(redirectedFileName, ".apt") != 0, ("multiple levels of indirection found for appearance template redirector files %s(%s)", fileName, redirectedFileName)); + + //-- add it to the redirector map + iter = ms_redirectorMap.insert(RedirectorMap::value_type(new PersistentCrcString(actualFileName), new PersistentCrcString(redirectedFileName, true))).first; + + iff.exitChunk(TAG_NAME); + iff.exitForm(TAG_0000); + iff.exitForm(TAG_APT); + } + + //-- create the target name instead + return create(iter->second->getString()); + } + + //-- search for the appearance in the named list + { + NamedTemplates::iterator iter = ms_namedTemplates.find((const CrcString*)&actualFileName); + if (iter != ms_namedTemplates.end()) + return iter->second; + } + + AppearanceTemplate *appearanceTemplate = 0; + + //-- search for the appearance in the named timed list + if (ms_useTimedTemplates) + { + NamedTimedTemplates::iterator iter = ms_namedTimedTemplates.find((const CrcString*)&actualFileName); + if (iter != ms_namedTimedTemplates.end()) + { + appearanceTemplate = iter->second.second; + ms_namedTimedTemplates.erase(iter); + } + } + + DEBUG_REPORT_LOG(ms_logCreate, ("Creating appearance %s\n", actualFileName.getString())); + + //-- hack to asynchronously load .msh files + if (!appearanceTemplate && AsynchronousLoader::isEnabled() && (strstr(actualFileName.getString(), ".msh") != 0 || strstr(actualFileName.getString(), ".MSH") != 0)) + { + // DEBUG_REPORT_LOG_PRINT(true, ("Loading mesh %s\n", actualFileName.getString())); + TagBindingMap::iterator iter = ms_tagBindingMap.find(TAG_MESH); + if (iter != ms_tagBindingMap.end()) + appearanceTemplate = iter->second(actualFileName.getString(), NULL); + } + + //-- we now need to create the appearance from disk + if (!appearanceTemplate) + { + Iff iff; + if (!iff.open(actualFileName.getString(), true)) + FATAL(true, ("Could not open appearance file %s", actualFileName.getString())); + + const Tag tag = iff.getCurrentName(); + TagBindingMap::iterator iter = ms_tagBindingMap.find(tag); + if (iter != ms_tagBindingMap.end()) + appearanceTemplate = iter->second(actualFileName.getString(), &iff); + else + { + char tagString[5]; + ConvertTagToString(tag, tagString); + DEBUG_FATAL(true, ("AppearanceTemplate binding %s not found", tagString)); + } + } + + //-- add the appearance template to the named list + if (appearanceTemplate) + { + addNamedAppearanceTemplate(appearanceTemplate); + } + + return appearanceTemplate; +} + +// ---------------------------------------------------------------------- +/** + * Add an anonymous appearance template to the AppearanceTemplateList. + * + * @param appearanceTemplate AppearanceTemplate to add + */ + +void AppearanceTemplateListNamespace::addAnonymousAppearanceTemplate(AppearanceTemplate *const appearanceTemplate) +{ + NOT_NULL(appearanceTemplate); + + //-- add to anonymous list + std::pair result = ms_anonymousTemplates.insert(appearanceTemplate); + + //-- make sure it's not already there + DEBUG_FATAL(!result.second, ("tried to add an existing anonymous appearanceTemplate")); + UNREF(result); +} + +// ---------------------------------------------------------------------- +/** + * Add a named appearance template to the AppearanceTemplateList. + * + * @param appearanceTemplate AppearanceTemplate to add + */ + +void AppearanceTemplateListNamespace::addNamedAppearanceTemplate(AppearanceTemplate *const appearanceTemplate) +{ + NOT_NULL(appearanceTemplate); + + //-- add to named list + std::pair result = ms_namedTemplates.insert(std::make_pair(&appearanceTemplate->getCrcName(), appearanceTemplate)); + + //-- make sure it's not already there + DEBUG_FATAL(!result.second, ("tried to add existing named appearanceTemplate %s", appearanceTemplate->getName())); + UNREF(result); +} + +// ---------------------------------------------------------------------- +/** + * Add a named timed appearance template to the AppearanceTemplateList. + * + * @param appearanceTemplate AppearanceTemplate to add + */ + +void AppearanceTemplateListNamespace::addNamedTimedAppearanceTemplate(AppearanceTemplate *const appearanceTemplate) +{ + NOT_NULL(appearanceTemplate); + + //-- add to named list + std::pair result = ms_namedTimedTemplates.insert(std::make_pair(&appearanceTemplate->getCrcName(), std::make_pair(ms_keepTime + Random::randomReal(ms_keepEpsilon), appearanceTemplate))); + + //-- make sure it's not already there + DEBUG_FATAL(!result.second, ("tried to add existing named timed appearanceTemplate %s", appearanceTemplate->getName())); + UNREF(result); +} + +// ---------------------------------------------------------------------- +/** + * Remove an appearance template from the AppearanceTemplateList. + * + * @param appearanceTemplate AppearanceTemplate to remove + */ + +void AppearanceTemplateListNamespace::removeAppearanceTemplate(AppearanceTemplate *const appearanceTemplate) +{ + NOT_NULL(appearanceTemplate); + CrcLowerString const & crcName = appearanceTemplate->getCrcName(); + char const * const crcString = crcName.getString(); + + if (crcString && *crcString) + { + //-- remove appearance template from the named list + NamedTemplates::iterator iter = ms_namedTemplates.find((const CrcString*)&appearanceTemplate->getCrcName()); + if (iter != ms_namedTemplates.end()) + ms_namedTemplates.erase(iter); + else + DEBUG_FATAL(true, ("AppearanceTemplateListNamespace::removeAppearanceTemplate: could not find appearance template %s in named list", crcString)); + } + else + { + //-- remove appearance template from the anonymous list + AnonymousTemplates::iterator iter = ms_anonymousTemplates.find(appearanceTemplate); + if (iter != ms_anonymousTemplates.end()) + ms_anonymousTemplates.erase(iter); + else + DEBUG_FATAL(true, ("AppearanceTemplateListNamespace::removeAppearanceTemplate: could not find anonymous appearance template in anonymous list")); + } +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateListNamespace::debugReport() +{ +#ifdef _DEBUG + DEBUG_REPORT_PRINT(true, ("Tags installed = %i\n", ms_tagBindingMap.size())); + DEBUG_REPORT_PRINT(true, ("Named templates = %i\n", ms_namedTemplates.size())); + DEBUG_REPORT_PRINT(true, ("Named timed templates = %i\n", ms_namedTimedTemplates.size())); + DEBUG_REPORT_PRINT(true, ("Anonymous templates = %i\n", ms_anonymousTemplates.size())); +#endif +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateListNamespace::debugReportVerbose() +{ +#ifdef _DEBUG + DEBUG_REPORT_PRINT(true, ("AppearanceTemplates loaded:\n")); + + DEBUG_OUTPUT_STATIC_VIEW_BEGINFRAME("Engine\\AppearanceTemplateList"); + DEBUG_OUTPUT_STATIC_VIEW("Engine\\AppearanceTemplateList", ("AppearanceTemplates loaded:\n")); + + for (NamedTemplates::iterator iter = ms_namedTemplates.begin(); iter != ms_namedTemplates.end(); ++iter) + { + const AppearanceTemplate *const t = (*iter).second; + DEBUG_REPORT_PRINT(true, (" %s %d\n", t->getCrcName().getString(), t->getReferenceCount())); + DEBUG_OUTPUT_STATIC_VIEW("Engine\\AppearanceTemplateList", (" %s %d\n", t->getCrcName().getString(), t->getReferenceCount())); + UNREF(t); + } + + DEBUG_OUTPUT_STATIC_VIEW_ENDFRAME("Engine\\AppearanceTemplateList"); +#endif +} + +// ---------------------------------------------------------------------- + +void AppearanceTemplateListNamespace::debugReportTimedTemplates() +{ +#ifdef _DEBUG + for (NamedTimedTemplates::iterator iter = ms_namedTimedTemplates.begin(); iter != ms_namedTimedTemplates.end(); ++iter) + DEBUG_REPORT_PRINT(true, ("% 2.1f %s\n", iter->second.first, iter->first->getString())); +#endif +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.h b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.h new file mode 100644 index 00000000..78d8df40 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/AppearanceTemplateList.h @@ -0,0 +1,62 @@ +// ====================================================================== +// +// AppearanceTemplateList.h +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2000-2002 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_AppearanceTemplateList_H +#define INCLUDED_AppearanceTemplateList_H + +// ====================================================================== + +#include "sharedFoundation/Tag.h" + +class Appearance; +class AppearanceTemplate; +class Iff; + +// ====================================================================== + +class AppearanceTemplateList +{ +public: + + typedef AppearanceTemplate *(*CreateFunction)(const char *name, Iff *iff); + +public: + + static void install(bool useTimedTemplates, bool ensureDefaultAppearanceExists); + + static void assignBinding(Tag tag, CreateFunction createFunction); + static void removeBinding(Tag tag); + + static void update(float elapsedTime); + static void setAllowTimedTemplates (bool allowTimedTemplates); + + static const AppearanceTemplate *fetch(const char *fileName); + static const AppearanceTemplate *fetch(const char *fileName, bool & found); + static const AppearanceTemplate *fetch(Iff *iff); + static const AppearanceTemplate *fetch(const AppearanceTemplate *appearanceTemplate); + static const AppearanceTemplate *fetchNew(AppearanceTemplate *appearanceTemplate); + static void release(const AppearanceTemplate *appearanceTemplate); + + static Appearance *createAppearance(const char *fileName); + + static const char* getDefaultAppearanceTemplateName(); + + static void garbageCollect (); + +private: + + // disabled + AppearanceTemplateList(); + AppearanceTemplateList(const AppearanceTemplateList &); + AppearanceTemplateList &operator =(const AppearanceTemplateList &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.cpp b/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.cpp new file mode 100644 index 00000000..7efd09ed --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.cpp @@ -0,0 +1,34 @@ +// ====================================================================== +// +// Hardpoint.cpp +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Hardpoint.h" + +// ====================================================================== + +Hardpoint::Hardpoint (const char* newName, const Transform& newTransform) : + m_name (newName, false), + m_transform (newTransform) +{ +} + +// ---------------------------------------------------------------------- + +CrcString const& Hardpoint::getName () const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +Transform const& Hardpoint::getTransform () const +{ + return m_transform; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.h b/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.h new file mode 100644 index 00000000..8ad1e08f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Hardpoint.h @@ -0,0 +1,91 @@ +// ====================================================================== +// +// HardPoint.h +// Copyright 2000 - 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Hardpoint_H +#define INCLUDED_Hardpoint_H + +// ====================================================================== + +#include "sharedFoundation/PersistentCrcString.h" +#include "sharedMath/Transform.h" + +// ====================================================================== + +class Hardpoint +{ +public: + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct LessNameComparator + { + bool operator () (Hardpoint const* lhs, Hardpoint const* rhs) const; + bool operator () (CrcString const& lhs, Hardpoint const* rhs) const; + bool operator () (Hardpoint const* lhs, CrcString const& rhs) const; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef const Hardpoint* ConstIterator; + +public: + + Hardpoint (const char* newName, const Transform& newTransform); + + CrcString const& getName () const; + Transform const& getTransform () const; + +private: + + // Disabled. + Hardpoint (void); + Hardpoint (const Hardpoint&); + Hardpoint& operator= (const Hardpoint&); + +private: + + PersistentCrcString const m_name; + Transform const m_transform; + +}; + +// ====================================================================== +// struct LessNameComparator +// ====================================================================== + +// Define these comparator functions inline so that STL sorts/searches are inlined. + +inline bool Hardpoint::LessNameComparator::operator () (Hardpoint const* lhs, Hardpoint const* rhs) const +{ + NOT_NULL (lhs); + NOT_NULL (rhs); + + return lhs->getName () < rhs->getName (); +} + +// ---------------------------------------------------------------------- + +inline bool Hardpoint::LessNameComparator::operator () (CrcString const& lhs, Hardpoint const* rhs) const +{ + NOT_NULL (rhs); + + return lhs < rhs->getName (); +} + +// ---------------------------------------------------------------------- + +inline bool Hardpoint::LessNameComparator::operator () (Hardpoint const* lhs, CrcString const& rhs) const +{ + NOT_NULL (lhs); + + return lhs->getName () < rhs; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.cpp b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.cpp new file mode 100644 index 00000000..6f00dbe7 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.cpp @@ -0,0 +1,21 @@ +// ====================================================================== +// +// NoRenderAppearance.cpp +// Portions copyright 2004 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/NoRenderAppearance.h" + +#include "sharedObject/NoRenderAppearanceTemplate.h" + +// ====================================================================== + +NoRenderAppearance::NoRenderAppearance(NoRenderAppearanceTemplate const * myAppearanceTemplate) +: Appearance(myAppearanceTemplate) +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.h b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.h new file mode 100644 index 00000000..6db598fb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearance.h @@ -0,0 +1,38 @@ +// ====================================================================== +// +// NoRenderAppearance.h +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001, 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_NoRenderAppearance_H +#define INCLUDED_NoRenderAppearance_H + +// ====================================================================== + +class NoRenderAppearanceTemplate; + +#include "sharedObject/Appearance.h" + +// ====================================================================== + +class NoRenderAppearance : public Appearance +{ + friend class NoRenderAppearanceTemplate; + +private: + + NoRenderAppearance(NoRenderAppearanceTemplate const * appearanceTemplate); + +private: + // disabled + NoRenderAppearance(); + NoRenderAppearance(NoRenderAppearance const &); + NoRenderAppearance & operator = (NoRenderAppearance const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.cpp b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.cpp new file mode 100644 index 00000000..36e50b34 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.cpp @@ -0,0 +1,64 @@ +// ====================================================================== +// +// NoRenderAppearanceTemplate.cpp +// Portions copyright 2004 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/NoRenderAppearanceTemplate.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/Tag.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/NoRenderAppearance.h" + +// ====================================================================== + +namespace NoRenderAppearanceTemplateNamespace +{ + const Tag TAG_NRND = TAG(N,R,N,D); + + AppearanceTemplate *create(const char *newName, Iff *iff); +}; +using namespace NoRenderAppearanceTemplateNamespace; + +// ====================================================================== + +void NoRenderAppearanceTemplate::install() +{ + AppearanceTemplateList::assignBinding(TAG_NRND, NoRenderAppearanceTemplateNamespace::create); +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate *NoRenderAppearanceTemplateNamespace::create(const char *newName, Iff *iff) +{ + return new NoRenderAppearanceTemplate(newName, iff); +} + +// ====================================================================== + + +NoRenderAppearanceTemplate::NoRenderAppearanceTemplate(const char *name, Iff *iff) +: AppearanceTemplate(name) +{ + iff->enterForm(TAG_NRND); + iff->exitForm(TAG_NRND); +} + +// ---------------------------------------------------------------------- + +NoRenderAppearanceTemplate::~NoRenderAppearanceTemplate() +{ +} + +// ---------------------------------------------------------------------- + +Appearance * NoRenderAppearanceTemplate::createAppearance() const +{ + return new NoRenderAppearance(this); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.h b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.h new file mode 100644 index 00000000..90de705f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/NoRenderAppearanceTemplate.h @@ -0,0 +1,40 @@ +// ====================================================================== +// +// NoRenderAppearanceTemplate.h +// Portions copyright 2004 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_NoRenderAppearanceTemplate_H +#define INCLUDED_NoRenderAppearanceTemplate_H + +// ====================================================================== + +#include "sharedObject/AppearanceTemplate.h" + +// ====================================================================== + +class NoRenderAppearanceTemplate : public AppearanceTemplate +{ +public: + + static void install(); + +public: + + NoRenderAppearanceTemplate(const char *name, Iff *iff); + virtual ~NoRenderAppearanceTemplate(); + + virtual Appearance * createAppearance() const; + +private: + + NoRenderAppearanceTemplate(); + NoRenderAppearanceTemplate(NoRenderAppearanceTemplate const &); + NoRenderAppearanceTemplate & operator = (NoRenderAppearanceTemplate const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.cpp b/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.cpp new file mode 100644 index 00000000..69ad0e28 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.cpp @@ -0,0 +1,25 @@ +// ====================================================================== +// +// TextAppearance.cpp +// Copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/TextAppearance.h" + +// ====================================================================== + +TextAppearance::TextAppearance () : + Appearance (0) +{ +} + +// ---------------------------------------------------------------------- + +TextAppearance::~TextAppearance () +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.h b/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.h new file mode 100644 index 00000000..6e5bad6e --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/TextAppearance.h @@ -0,0 +1,38 @@ +// ====================================================================== +// +// TextAppearance.h +// Copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_TextAppearance_H +#define INCLUDED_TextAppearance_H + +// ====================================================================== + +#include "sharedObject/Appearance.h" + +class VectorArgb; + +// ====================================================================== + +class TextAppearance : public Appearance +{ +public: + + TextAppearance (); + virtual ~TextAppearance ()=0; + + virtual void setText(const char* text)=0; + virtual void setColor(const VectorArgb& color)=0; + +private: + + TextAppearance (const TextAppearance& rhs); + TextAppearance& operator= (const TextAppearance& rhs); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.cpp b/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.cpp new file mode 100644 index 00000000..f3c09b07 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.cpp @@ -0,0 +1,36 @@ +// ====================================================================== +// +// Tweakable.cpp +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Tweakable.h" + +// ====================================================================== + +Tweakable::~Tweakable() +{ +} + +// ---------------------------------------------------------------------- + +float Tweakable::getTweakValue ( int whichValue ) const +{ + UNREF(whichValue); + + return 0.0f; +} + +// ---------------------------------------------------------------------- + +void Tweakable::setTweakValue ( int whichValue, float newValue ) +{ + UNREF(whichValue); + UNREF(newValue); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.h b/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.h new file mode 100644 index 00000000..bcaaa66e --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/appearance/Tweakable.h @@ -0,0 +1,40 @@ +// ====================================================================== +// +// Tweakable.h +// Portions copyright 1999 Bootprint Entertainment +// Portions copyright 2001, 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Tweakable_H +#define INCLUDED_Tweakable_H + +// ====================================================================== +// Simple interface for setting/getting tweak values on objects. + +class Tweakable +{ +public: + + Tweakable(); + virtual ~Tweakable(); + + virtual float getTweakValue ( int whichValue ) const; + virtual void setTweakValue ( int whichValue, float newValue ); + +private: + + Tweakable(const Tweakable &); + Tweakable &operator =(const Tweakable &); +}; + +// ====================================================================== + +inline Tweakable::Tweakable() +{ +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.cpp b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.cpp new file mode 100644 index 00000000..9ac129fb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.cpp @@ -0,0 +1,154 @@ +// ====================================================================== +// +// ArrangementDescriptor.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ArrangementDescriptor.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedObject/ArrangementDescriptorList.h" +#include "sharedObject/SlotId.h" +#include "sharedObject/SlotIdManager.h" + +#include + +// ====================================================================== + +const Tag TAG_ARG = TAG3(A,R,G); +const Tag TAG_ARGD = TAG(A,R,G,D); + +// ====================================================================== + +ArrangementDescriptor::ArrangementDescriptor(Iff &iff, const CrcLowerString &name) +: m_name(new CrcLowerString(name)), + m_referenceCount(0), + m_arrangements(new ArrangementVector()) +{ + // load instance data from iff + iff.enterForm(TAG_ARGD); + + // handle version loading + const Tag version = iff.getCurrentName(); + if (version == TAG_0000) + load_0000(iff); + else + { + char buffer[5]; + + ConvertTagToString(version, buffer); + FATAL(true, ("unsupported ArrangementDescriptor version [%s]", buffer)); + } + + iff.exitForm(TAG_ARGD); +} + +// ---------------------------------------------------------------------- + +const CrcLowerString &ArrangementDescriptor::getName() const +{ + return *m_name; +} + +// ---------------------------------------------------------------------- + +int ArrangementDescriptor::getReferenceCount() const +{ + return m_referenceCount; +} + +// ---------------------------------------------------------------------- + +void ArrangementDescriptor::fetch() const +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- + +void ArrangementDescriptor::release() const +{ + --m_referenceCount; + + // check if we need to delete this one + if (m_referenceCount < 1) + { + ArrangementDescriptorList::stopTracking(*this); + delete const_cast(this); + } +} + +// ---------------------------------------------------------------------- + +int ArrangementDescriptor::getArrangementCount() const +{ + return static_cast(m_arrangements->size()); +} + +// ---------------------------------------------------------------------- + +const ArrangementDescriptor::SlotIdVector &ArrangementDescriptor::getArrangement(int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, static_cast(m_arrangements->size())); + + return (*m_arrangements)[static_cast(index)]; +} + +// ====================================================================== + +ArrangementDescriptor::~ArrangementDescriptor() +{ + DEBUG_WARNING(m_referenceCount != 0, ("non-zero reference count upon deletion: bad reference handling (%d)", m_referenceCount)); + + delete m_arrangements; + delete m_name; +} + +// ---------------------------------------------------------------------- + +void ArrangementDescriptor::load_0000(Iff &iff) +{ + iff.enterForm(TAG_0000); + { + CrcLowerString slotName(""); + char buffer[1024]; + + SlotIdVector arrangement; + + // load the arrangement list + while (!iff.atEndOfForm()) + { + iff.enterChunk(TAG_ARG); + { + // load the arrangement + while (iff.getChunkLengthLeft()) + { + // load slot name + iff.read_string(buffer, sizeof(buffer) - 1); + slotName.setString(buffer); + + // convert slot name to SlotId + const SlotId slotId = SlotIdManager::findSlotId(slotName); + if (slotId == SlotId::invalid) + WARNING(true, ("ArrangementDescriptor [%s] specified invalid slot name [%s], ignoring", m_name->getString(), slotName.getString())); + else + arrangement.push_back(slotId); + } + } + iff.exitChunk(TAG_ARG); + + // add arrangement to list of arrangements + m_arrangements->push_back(arrangement); + + // cleanup temp vector + arrangement.clear(); + } + } + iff.exitForm(TAG_0000); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.h b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.h new file mode 100644 index 00000000..3dca2eaf --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptor.h @@ -0,0 +1,66 @@ +// ====================================================================== +// +// ArrangementDescriptor.h +// Copyright 2001 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ArrangementDescriptor_H +#define INCLUDED_ArrangementDescriptor_H + +// ====================================================================== + +class CrcLowerString; +class Iff; +class SlotId; + +// ====================================================================== + +class ArrangementDescriptor +{ +friend class ArrangementDescriptorList; + +public: + + typedef stdvector::fwd SlotIdVector; + +public: + + ArrangementDescriptor(Iff &iff, const CrcLowerString &name); + + const CrcLowerString &getName() const; + int getReferenceCount() const; + + void fetch() const; + void release() const; + + int getArrangementCount() const; + const SlotIdVector &getArrangement(int index) const; + +private: + + typedef stdvector::fwd ArrangementVector; + +private: + + ~ArrangementDescriptor(); + + void load_0000(Iff &iff); + + // disabled + ArrangementDescriptor(const ArrangementDescriptor&); + ArrangementDescriptor &operator =(const ArrangementDescriptor&); + +private: + + CrcLowerString *m_name; + mutable int m_referenceCount; + + ArrangementVector *m_arrangements; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.cpp b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.cpp new file mode 100644 index 00000000..31de898d --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.cpp @@ -0,0 +1,156 @@ +// ====================================================================== +// +// ArrangementDescriptorList.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ArrangementDescriptorList.h" + +#include "sharedDebug/DataLint.h" +#include "sharedFile/Iff.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedObject/ArrangementDescriptor.h" + +#include +#include + +// ====================================================================== + +bool ArrangementDescriptorList::ms_installed; +ArrangementDescriptorList::DescriptorMap *ArrangementDescriptorList::ms_descriptors; + +ConstCharCrcLowerString ArrangementDescriptorList::ms_defaultFilename("arrangement/arrangement_none.iff"); + + +// ====================================================================== + +void ArrangementDescriptorList::install() +{ + DEBUG_FATAL(ms_installed, ("ArrangementDescriptorList already installed")); + + ms_descriptors = new DescriptorMap(); + ms_installed = true; + + ExitChain::add(remove, "ArrangementDescriptorList"); +} + +// ---------------------------------------------------------------------- + +const ArrangementDescriptor *ArrangementDescriptorList::fetch(const CrcLowerString &filename) +{ + DEBUG_FATAL(!ms_installed, ("ArrangementDescriptorList not installed")); + + ArrangementDescriptor *descriptor = 0; + + //-- check if we've got this one cached + DescriptorMap::iterator lowerBoundResult = ms_descriptors->lower_bound(&filename); + if ((lowerBoundResult != ms_descriptors->end()) && !ms_descriptors->key_comp()(&filename, lowerBoundResult->first)) + { + // it's cached, return it + descriptor = lowerBoundResult->second; + } + else + { + // it's not available + Iff iff; + + if (!iff.open(filename.getString(), true)) + { + //-- make sure we didn't just fail on the default filename + if (filename != ms_defaultFilename) + { + WARNING(true, ("ArrangementDescriptor file [%s] does not exist, using default", filename.getString())); + return fetch(ms_defaultFilename); + } + else + { + WARNING(true, ("default ArrangementDescriptor [%s] could not be loaded, returning NULL ArrangementDescriptor", filename.getString())); + return 0; + } + } + +#ifdef _DEBUG + DataLint::pushAsset(filename.getString()); +#endif // _DEBUG + + //-- load it + descriptor = new ArrangementDescriptor(iff, filename); + +#ifdef _DEBUG + DataLint::popAsset(); +#endif // _DEBUG + + //-- add to managed container + IGNORE_RETURN(ms_descriptors->insert(lowerBoundResult, DescriptorMap::value_type(&descriptor->getName(), descriptor))); + } + + // we should have a valid slot descriptor here + NOT_NULL(descriptor); + + //-- bump up reference count + descriptor->fetch(); + + return descriptor; +} + +// ---------------------------------------------------------------------- + +const ArrangementDescriptor *ArrangementDescriptorList::fetch(const std::string &filename) +{ + DEBUG_FATAL(!ms_installed, ("ArrangementDescriptorList not installed")); + + return fetch(CrcLowerString(filename.c_str())); +} + +// ====================================================================== + +void ArrangementDescriptorList::remove() +{ + DEBUG_FATAL(!ms_installed, ("ArrangementDescriptorList not installed")); + + //-- handle leaks + if (!ms_descriptors->empty()) + { + DEBUG_WARNING(true, ("ArrangementDescriptorList detected %u ArrangementDescriptor leaks:", ms_descriptors->size())); + + const DescriptorMap::iterator endIt = ms_descriptors->end(); + for (DescriptorMap::iterator it = ms_descriptors->begin(); it != endIt; ++it) + { + ArrangementDescriptor *const descriptor = it->second; + + DEBUG_WARNING(descriptor, ("-- leaked ArrangementDescriptor [%s]", descriptor->getName().getString())); + delete descriptor; + } + } + + delete ms_descriptors; + + ms_installed = false; +} + +// ---------------------------------------------------------------------- + +void ArrangementDescriptorList::stopTracking(const ArrangementDescriptor &descriptor) +{ + DEBUG_FATAL(!ms_installed, ("ArrangementDescriptorList not installed")); + + //-- find the descriptor within our managed container + const CrcLowerString &filename = descriptor.getName(); + + DescriptorMap::iterator lowerBoundResult = ms_descriptors->lower_bound(&filename); + if ((lowerBoundResult == ms_descriptors->end()) || ms_descriptors->key_comp()(&filename, lowerBoundResult->first)) + { + // Specified descriptor not managed. It could be unnamed (i.e. anonymous). + return; + } + + //-- remove from managed container + ms_descriptors->erase(lowerBoundResult); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.h b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.h new file mode 100644 index 00000000..4d517a88 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ArrangementDescriptorList.h @@ -0,0 +1,52 @@ +// ====================================================================== +// +// ArrangementDescriptorList.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ArrangementDescriptorList_H +#define INCLUDED_ArrangementDescriptorList_H + +// ====================================================================== + +class ArrangementDescriptor; +class ConstCharCrcLowerString; +class CrcLowerString; +class LessPointerComparator; + +// ====================================================================== + +class ArrangementDescriptorList +{ +friend class ArrangementDescriptor; + +public: + + static void install(); + + static const ArrangementDescriptor *fetch(const CrcLowerString &filename); + static const ArrangementDescriptor *fetch(const std::string &filename); + +private: + + typedef stdmap::fwd DescriptorMap; + +private: + + static void remove(); + static void stopTracking(const ArrangementDescriptor &descriptor); + +private: + + static bool ms_installed; + static DescriptorMap *ms_descriptors; + + static ConstCharCrcLowerString ms_defaultFilename; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.cpp b/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.cpp new file mode 100644 index 00000000..1a25f0cd --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.cpp @@ -0,0 +1,81 @@ +// ====================================================================== +// +// ContainedByProperty.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ContainedByProperty.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/Container.h" +#include "sharedObject/Object.h" +#include "sharedObject/NetworkIdManager.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(ContainedByProperty, true, 0, 0, 0); + +// ====================================================================== + +PropertyId ContainedByProperty::getClassPropertyId() +{ + return PROPERTY_HASH(ContainedBy, 0x704360EC); +} + +// ====================================================================== + +ContainedByProperty::ContainedByProperty(Object& thisObject, Object* containedByObject) : +Property(getClassPropertyId(), thisObject), +m_containedBy(CachedNetworkId::cms_cachedInvalid) +{ + if (containedByObject) + m_containedBy = CachedNetworkId(*containedByObject); +} + +//------------------------------------------------------------------------- + +ContainedByProperty::~ContainedByProperty() +{ +} + +// ====================================================================== +/** + * Return the container that contains the object that has this ContainedBy + * property. + * + * @return Pointer to the object that contains the object with this + * ContainedByProperty. Returns NULL if the object isn't + * contained by anything at the moment. + */ + +Object* ContainedByProperty::getContainedBy() const +{ + return m_containedBy.getObject(); +} + +// ---------------------------------------------------------------------- + +const NetworkId& ContainedByProperty::getContainedByNetworkId() const +{ + return m_containedBy; +} + +// ---------------------------------------------------------------------- + +void ContainedByProperty::setContainedBy(const NetworkId & id, bool local) +{ + if (m_containedBy != id) + { + NetworkId oldValue = m_containedBy; + m_containedBy = id; + getOwner().containedByModified(oldValue, id, local); + } +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.h b/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.h new file mode 100644 index 00000000..2f44b2b5 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/ContainedByProperty.h @@ -0,0 +1,48 @@ +// ====================================================================== +// +// ContainedByProperty.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ContainedByProperty_H +#define INCLUDED_ContainedByProperty_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/CachedNetworkId.h" +#include "sharedObject/Property.h" + +// ====================================================================== + +class ContainedByProperty : public Property +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + static PropertyId getClassPropertyId(); + +public: + ContainedByProperty(Object& thisObject, Object* containedByObject); + ~ContainedByProperty(); + + Object* getContainedBy() const; + const NetworkId & getContainedByNetworkId() const; + + void setContainedBy(const NetworkId &id, bool local = true); + +private: + CachedNetworkId m_containedBy; + + ContainedByProperty(); + ContainedByProperty(const ContainedByProperty&); + ContainedByProperty& operator= (const ContainedByProperty&); +}; + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/container/Container.cpp b/engine/shared/library/sharedObject/src/shared/container/Container.cpp new file mode 100644 index 00000000..9640a335 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/Container.cpp @@ -0,0 +1,856 @@ +// ====================================================================== +// +// Container.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Container.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Object.h" + +#include + +// ====================================================================== +//Lint suppressions. + +//lint -esym(613, ContainerIterator::m_iterator) // (Warning -- Possible use of null pointer 'ContainerIterator::m_iterator' ) // This is an opaque data type to us. We can only check against a container::end(). +//lint -esym(1540, ContainerIterator::m_iterator) // (Warning -- Pointer member 'ContainerIterator::m_iterator' neither freed nor zero'ed by destructor -- Effective C++ #6) // It's okay, the iterator type is opaque to us, we have no idea it's a pointer. +//lint -esym(1554, ContainerIterator::m_iterator) // (Warning -- Direct copy of pointer 'ContainerIterator::m_iterator'. // It's okay, the iterator type is opaque to us, we have no idea it's a pointer. +//lint -esym(1555, ContainerIterator::m_iterator) // (Warning -- Direct pointer copy of member 'ContainerIterator::m_iterator' within copy assignment operator: 'ContainerIterator::operator=(const ContainerIterator &) // Opaque type, we don't know its a pointer. +//lint -esym(1555, ContainerIterator::m_owner) // (Warning -- Direct pointer copy of member 'ContainerIterator::m_owner' within copy assignment operator: 'ContainerIterator::operator=(const ContainerIterator &) // We do not own this memory, so it's okay to overwrite the pointer. We can't leak it. + +//lint -esym(613, ContainerConstIterator::m_iterator) // (Warning -- Possible use of null pointer 'ContainerConstIterator::m_iterator' ) // This is an opaque data type to us. We can only check against a container::end(). +//lint -esym(1540, ContainerConstIterator::m_iterator) // (Warning -- Pointer member 'ContainerConstIterator::m_iterator' neither freed nor zero'ed by destructor -- Effective C++ #6) // It's okay, the iterator type is opaque to us, we have no idea it's a pointer. +//lint -esym(1554, ContainerConstIterator::m_iterator) // (Warning -- Direct copy of pointer 'ContainerConstIterator::m_iterator'. // It's okay, the iterator type is opaque to us, we have no idea it's a pointer. +//lint -esym(1555, ContainerConstIterator::m_iterator) // (Warning -- Direct pointer copy of member 'ContainerConstIterator::m_iterator' within copy assignment operator: 'ContainerConstIterator::operator=(const ContainerConstIterator &) // Opaque type, we don't know its a pointer. +//lint -esym(1555, ContainerConstIterator::m_owner) // (Warning -- Direct pointer copy of member 'ContainerConstIterator::m_owner' within copy assignment operator: 'ContainerConstIterator::operator=(const ContainerConstIterator &) // We do not own this memory, so it's okay to overwrite the pointer. We can't leak it. + +//----------------------------------------------------------------------- + +namespace ContainerNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + int checkDepth(const Container& container) + { + int count = 0; + const ContainedByProperty* parentCpb = container.getOwner().getContainedByProperty(); + if (!parentCpb) + return count; + + const Object* parentObject = parentCpb->getContainedBy(); + if (!parentObject) + return count; + + while(parentObject) + { + ++count; + parentCpb = parentObject->getContainedByProperty(); + if (!parentCpb) + return count; + parentObject = parentCpb->getContainedBy(); + } + return count; + } + +} + +using namespace ContainerNamespace; + +//----------------------------------------------------------------------- + +ContainerIterator::ContainerIterator() : +m_iterator(0), +m_owner(0) +{ +} +//----------------------------------------------------------------------- + +ContainerIterator::ContainerIterator(Container & owner, const std::vector::iterator & iter) : +m_iterator(iter), +m_owner(&owner) +{ +} +//----------------------------------------------------------------------- + +ContainerIterator::~ContainerIterator() +{ + // We don't own the owner pointer. + m_owner = 0; +} +//----------------------------------------------------------------------- + +ContainerIterator::ContainerIterator(const ContainerIterator & rhs) : +m_iterator(rhs.m_iterator), +m_owner(rhs.m_owner) //lint !e1554 // Direct copy of pointer member. // @todo revisit. There doesn't appear to be any mechanism in place to guarantee the owner container sticks around for the iterator. This is dangerous. +{ +} +//----------------------------------------------------------------------- + +ContainerIterator & ContainerIterator::operator= (const ContainerIterator & rhs) +{ + if ((&rhs == this) || (rhs == *this)) + return *this; + m_iterator = rhs.m_iterator; + m_owner = rhs.m_owner; + return *this; +} +//----------------------------------------------------------------------- + +CachedNetworkId & ContainerIterator::operator*() +{ + // @todo fix this interface -- it is broken. It is possible to + // construct a ContainerIterator with a NULL m_iterator, but there is + // no way to gracefully exit from this function since it requires a non-const + // reference. Otherwise I would return CachedNetworkId::cms_cachedIvalid. + NOT_NULL(m_owner); + DEBUG_FATAL(m_iterator == m_owner->m_contents.end(), ("Tried to dereference invalid iterator.\n")); + + return *m_iterator; +} + +//----------------------------------------------------------------------- + +bool ContainerIterator::operator==(const ContainerIterator & rhs) const +{ + return m_iterator == rhs.m_iterator; +} +//----------------------------------------------------------------------- + +bool ContainerIterator::operator!=(const ContainerIterator & rhs) const +{ + return !(rhs == *this); +} + + +ContainerIterator ContainerIterator::operator++(int tmp) +{ + UNREF(tmp); + ContainerIterator *retval = this; + ++(*this); + return *retval; +} +//----------------------------------------------------------------------- + +ContainerIterator& ContainerIterator::operator++() +{ + NOT_NULL(m_owner); + if (m_iterator == m_owner->m_contents.end()) + return *this; + + ++m_iterator; + while (m_iterator != m_owner->m_contents.end() && *m_iterator == NetworkId::cms_invalid) + { + ++m_iterator; + } + return *this; +} + +//----------------------------------------------------------------------- + +ContainerConstIterator::ContainerConstIterator() : +m_iterator(0), +m_owner(0) +{ +} +//----------------------------------------------------------------------- + +ContainerConstIterator::ContainerConstIterator(const Container & owner, const std::vector::const_iterator & iter) : +m_iterator(iter), +m_owner(&owner) +{ +} +//----------------------------------------------------------------------- + +ContainerConstIterator::~ContainerConstIterator() +{ + // We don't own the m_owner pointer. + m_owner = 0; +} +//----------------------------------------------------------------------- + +ContainerConstIterator::ContainerConstIterator(const ContainerConstIterator & rhs) : +m_iterator(rhs.m_iterator), +m_owner(rhs.m_owner) //lint !e1554 // Direct copy of pointer member. // @todo revisit. There doesn't appear to be any mechanism in place to guarantee the owner container sticks around for the iterator. This is dangerous. +{ +} +//----------------------------------------------------------------------- + +ContainerConstIterator & ContainerConstIterator::operator= (const ContainerConstIterator & rhs) +{ + if ((&rhs == this) || (rhs == *this)) + return *this; + m_iterator = rhs.m_iterator; + m_owner = rhs.m_owner; + return *this; +} +//----------------------------------------------------------------------- + +const CachedNetworkId & ContainerConstIterator::operator*() const +{ + // @todo fix this interface -- it is broken. It is possible to + // construct a ContainerIterator with a NULL m_iterator, but there is + // no way to gracefully exit from this function since it requires a non-const + // reference. Otherwise I would return CachedNetworkId::cms_cachedIvalid. + NOT_NULL(m_owner); + if (m_iterator == m_owner->m_contents.end()) + { + DEBUG_WARNING(true, ("Tried to dereference invalid iterator.\n")); + return CachedNetworkId::cms_cachedInvalid; + } + + return *m_iterator; +} + +//----------------------------------------------------------------------- + +bool ContainerConstIterator::operator==(const ContainerConstIterator & rhs) const +{ + return m_iterator == rhs.m_iterator; +} +//----------------------------------------------------------------------- + +bool ContainerConstIterator::operator!=(const ContainerConstIterator & rhs) const +{ + return !(rhs == *this); +} + +//----------------------------------------------------------------------- + +ContainerConstIterator ContainerConstIterator::operator++(int tmp) +{ + UNREF(tmp); + ContainerConstIterator *retval = this; + ++(*this); + return *retval; +} + +//----------------------------------------------------------------------- + +ContainerConstIterator& ContainerConstIterator::operator++() +{ + NOT_NULL(m_owner); + + if (m_iterator == m_owner->m_contents.end()) + return *this; + + ++m_iterator; + while (m_iterator != m_owner->m_contents.end() && *m_iterator == NetworkId::cms_invalid) + { + ++m_iterator; + } + + + return *this; +} + +//----------------------------------------------------------------------- + +Container::Container(PropertyId propertyId, Object& owner) : +Property(propertyId, owner), +m_changed(false), +m_contents(), +m_numContents(0) +{ +} + +//----------------------------------------------------------------------- + +Container::~Container() +{ + Contents::const_iterator i = m_contents.begin(); + for(;i != m_contents.end(); ++i) + { + if (*i != NetworkId::cms_invalid) //was getValue + { + Object *const object = i->getObject(); + if (object) + { + IGNORE_RETURN(AlterScheduler::removeObject(*object)); + delete object; + } + } + } +} + +//----------------------------------------------------------------------- + +ContainerIterator Container::begin() +{ + //Getting ready to put in fix for iterator code. + ContainerIterator ret(*this, m_contents.begin()); + while (ret.m_iterator != m_contents.end() && *ret == NetworkId::cms_invalid) + { + ++ret.m_iterator; + } + return ret; +} + +//----------------------------------------------------------------------- + +ContainerIterator Container::end() +{ + return ContainerIterator(*this, m_contents.end()); +} + +//----------------------------------------------------------------------- + +ContainerConstIterator Container::begin() const +{ + //Getting ready to put in fix for iterator code. + ContainerConstIterator ret(*this, m_contents.begin()); + while (ret.m_iterator != m_contents.end() && *ret == NetworkId::cms_invalid) + { + ++ret.m_iterator; + } + return ret; +} + +//----------------------------------------------------------------------- + +ContainerConstIterator Container::end() const +{ + return ContainerConstIterator(*this, m_contents.end()); +} + +//----------------------------------------------------------------------- + +int Container::addToContents(Object& item, ContainerErrorCode& error) +{ + error = CEC_Success; + + if (!mayAdd(item, error)) + return -1; + + ContainedByProperty * containedItem = item.getContainedByProperty(); + FATAL(!containedItem, ("Cannot add an item with no containedByProperty to a container.")); + if (containedItem->getContainedBy() && containedItem->getContainedBy() != &getOwner()) + { + WARNING_STRICT_FATAL(true, ("Cannot add an item [%s] to a container [%s] when it is already contained!", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_AlreadyIn; + return -1; + } + + if (ConfigSharedObject::getContainerLoopChecking()) + { + //Check that we don't introduce an infinite loop + //First check for container property. Only containers can introduce a loop + Container* contCheck = item.getContainerProperty(); + if (contCheck) + { + ContainedByProperty * cbIter = getOwner().getContainedByProperty(); + if (cbIter) + { + NetworkId iterId = cbIter->getContainedByNetworkId(); + if (iterId != NetworkId::cms_invalid) + { + std::vector checkVector; + checkVector.reserve(10); + checkVector.push_back(getOwner().getNetworkId()); + for( int count = 0; iterId != NetworkId::cms_invalid; ++count) + { + if (count > ConfigSharedObject::getContainerMaxDepth()) + { + DEBUG_FATAL(true, ("Too deep a container heirarchy")); + WARNING(true, ("Too deep a container heirarchy")); //lint !e527 // unreachable // reachable in release. + error = CEC_TooDeep; + return -1; + } + checkVector.push_back(iterId); + Object* obj = cbIter->getContainedBy(); + iterId = NetworkId::cms_invalid; + if (obj) + { + cbIter = obj->getContainedByProperty(); + if (cbIter) + { + iterId = cbIter->getContainedByNetworkId(); + } + } + + + } + if (std::find(checkVector.begin(), checkVector.end(), item.getNetworkId()) != checkVector.end()) + { + //detected a loop. + WARNING_STRICT_FATAL(true, ("Adding item %s to %s would have introduced a container loop", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_AlreadyIn; + return -1; + + } + } + } + + } + } + + if (checkDepth(*this) > ConfigSharedObject::getContainerMaxDepth()) + { + error = CEC_TooDeep; + return -1; + } + + if (isItemContained(item.getNetworkId(), error)) + { + WARNING_STRICT_FATAL(true, ("Cannot add an item [%s] to a container [%s] when it is already in it! This shouldn't happen because the item's contained by property says it is not in this container, but it is in the container's internal list.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_AlreadyIn; + return -1; + } + + const CachedNetworkId id(item); + + containedItem->setContainedBy(getOwner().getNetworkId()); + int retval = insertNewItem(id); + if (retval == -1) + error = CEC_Unknown; + return retval; +} + +//----------------------------------------------------------------------- + +PropertyId Container::getClassPropertyId() +{ + return PROPERTY_HASH(Container, 0x55DC5726); +} + +//----------------------------------------------------------------------- + +int Container::insertNewItem(const Container::ContainedItem& id) +{ + ContainerErrorCode tmp = CEC_Success;; + if (isItemContained(id, tmp)) + { + DEBUG_WARNING(true, ("Cannot add item [%s] to container [%s] when it is already in it!", id.getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + return -1; + } + + if (id == getOwner().getNetworkId()) + { + WARNING_STRICT_FATAL(true, ("Tried to add an item %s to itself!\n", id.getValueString().c_str())); + return -1; + } + + + Contents::iterator i = m_contents.begin(); + int count = 0; + ++m_numContents; + for(;i != m_contents.end(); ++i) + { + if (*i == NetworkId::cms_invalid) + { + (*i) = id; + return count; + } + ++count; + } + m_contents.push_back(id); + return count; +} + +//----------------------------------------------------------------------- + + +int Container::find(const NetworkId& item, ContainerErrorCode& error) const +{ + error = CEC_Success; + int count = 0; + Contents::const_iterator i = m_contents.begin(); + for(;i != m_contents.end(); ++i) + { + if ((*i) == item) + { + return count; + } + ++count; + } + error = CEC_NotFound; + return -1; +} + +//----------------------------------------------------------------------- + +int Container::getNumberOfItems (void) const +{ + return m_numContents; +} + +//----------------------------------------------------------------------- + +void Container::addToWorld() +{ + for (Contents::const_iterator i = m_contents.begin(); i != m_contents.end(); ++i) + { + Object *obj = (*i).getObject(); + if (obj && isContentItemExposedWith(*obj)) + obj->addToWorld(); + } +} + +//----------------------------------------------------------------------- + +void Container::removeFromWorld() +{ + for (Contents::const_iterator i = m_contents.begin(); i != m_contents.end(); ++i) + { + Object *obj = (*i).getObject(); + if (obj && isContentItemExposedWith(*obj)) + obj->removeFromWorld(); + } +} + +// ---------------------------------------------------------------------- +/** + * Returns true if the item is or would be observed with its container. + * + * This function can be called on an item in the container or an item + * that the caller already knows it will be putting in the container. + * + * If this function returns true, it indicates that the contained item + * should be added to the world and should be observed whenever the same + * happens to the container. In other words, the item within the container + * has the same visibility as the container itself. Mounts make use of this + * to expose the rider whenever the mount is exposed. + * + * Derived container class note: derived containers should chain up to + * this function first. If it returns true, you're done because that + * implies the container blanket-exposes all contents. If the function + * returns false, then do any container-specific checks that might + * allow this particular object to be exposed. Slotted containers work + * this way to allow slot-by-slot specification of observation + * characteristics. + * + * @param item the item that is contained or will soon be contained by + * the container. + * + * @return true if the item should be exposed with the same observation + * and world characterstics as the container. + */ + +bool Container::isContentItemObservedWith(Object const &item) const +{ + UNREF(item); + return false; +} + +//----------------------------------------------------------------------- +/** + * Returns true if the item should be in the world if its container is + * in the world. + * + * This function can be called on an item in the container or an item + * that the caller already knows it will be putting in the container. + * + * If this function returns true, it indicates that the contained item + * should be added to the world whenever the container is added to the world. + * + * Derived container class note: derived containers should chain up to + * this function first. If it returns true, you're done because that + * implies the container blanket-exposes all contents. If the function + * returns false, then do any container-specific checks that might + * allow this particular object to be exposed. Slotted containers work + * this way to allow slot-by-slot specification of exposing + * characteristics. + * + * @param item the item that is contained or will soon be contained by + * the container. + * + * @return true if the item should be exposed with the same observation + * and world characterstics as the container. + */ + +bool Container::isContentItemExposedWith(Object const &item) const +{ + UNREF(item); + return false; +} + +//----------------------------------------------------------------------- + +bool Container::canContentsBeObservedWith() const +{ + return false; +} + +//----------------------------------------------------------------------- + +void Container::alter(real time) +{ + FATAL(!Object::shouldObjectsAlterChildrenAndContents(), ("Container::alter called when containers should not be altering!")); + + std::vector objectsToDelete; + for (Contents::const_iterator i = m_contents.begin(); i != m_contents.end(); ++i) + { + Object *obj = (*i).getObject(); + if (obj) + { + if (obj->isInitialized() && !isContentItemExposedWith(*obj) && !obj->isChildObject()) + { + AlterScheduler::setMostRecentAlterTime(*obj); + if (obj->alter(time) == AlterResult::cms_kill) //lint !e777 // testing floats for equality // it's okay, set/compare against constants. + { + objectsToDelete.push_back(obj); + } + } + } + } + for (std::vector::iterator j = objectsToDelete.begin(); j != objectsToDelete.end(); ++j) + { + Object *const objectToKill = *j; + ContainerErrorCode error = CEC_Success; + IGNORE_RETURN(remove (*objectToKill, error)); + delete objectToKill; + } + objectsToDelete.clear(); +} + +//----------------------------------------------------------------------- + +void Container::conclude() +{ +} + +//----------------------------------------------------------------------- + + +bool Container::isItemContained (const NetworkId& item, ContainerErrorCode& error) const +{ + return (Container::find(item, error) != -1); +} + +//----------------------------------------------------------------------- + +bool Container::remove (Object &item, ContainerErrorCode& error) +{ + error = CEC_Unknown; + bool retval = false; + ContainedByProperty* property = item.getContainedByProperty(); + WARNING_STRICT_FATAL(!property, ("Cannot remove an item that has no containedby property")); + if (property) + { + if (property->getContainedBy() != &getOwner()) + { + WARNING_STRICT_FATAL(true, ("Cannot remove an item [%s] from container [%s] whose containedBy says it isn't in this container.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_NotFound; + return false; + } + retval = internalRemoveItem(item); + if (retval) + { + error = CEC_Success; + property->setContainedBy(NetworkId::cms_invalid); + } + } + return retval; +} + +//----------------------------------------------------------------------- + +const Container::ContainedItem& Container::getContents (int position) const +{ + DEBUG_FATAL(position > static_cast(m_contents.size()), ("Tried to index a container larger than the number of contents.")); + return m_contents[static_cast(position)]; +} + +//----------------------------------------------------------------------- + +void Container::debugPrint(std::string &buffer) const +{ + char tempBuffer[1024]; + + buffer += "====[BEGIN: container]====\n"; + + //-- List supported slots and container indices. + sprintf(tempBuffer, "container id [%s]: contains [%d] objects.\n", getOwner().getNetworkId().getValueString().c_str(), static_cast(m_contents.size())); + buffer += tempBuffer; + + int index = 0; + Contents::const_iterator const endIt = m_contents.end(); + for (Contents::const_iterator it = m_contents.begin(); it != endIt; ++it, ++index) + { + Object const *const object = it->getObject(); + + sprintf(tempBuffer, "\tindex [%d]: object id [%s], template [%s]\n", index, it->getValueString().c_str(), object ? object->getObjectTemplateName() : ""); + buffer += tempBuffer; + } + + buffer += "====[END: container]====\n"; +} + +// ---------------------------------------------------------------------- + +void Container::debugLog() const +{ +#ifdef _DEBUG + DEBUG_REPORT_LOG(true, ("====[BEGIN: container]====\n")); + + //-- List supported slots and container indices. + DEBUG_REPORT_LOG(true, ("container id [%s]: contains [%d] objects.\n", getOwner().getNetworkId().getValueString().c_str(), static_cast(m_contents.size()))); + + int index = 0; + Contents::const_iterator const endIt = m_contents.end(); + for (Contents::const_iterator it = m_contents.begin(); it != endIt; ++it, ++index) + { + Object const *const object = it->getObject(); + DEBUG_REPORT_LOG(true, ("\tindex [%d]: object id [%s], template [%s]\n", index, it->getValueString().c_str(), object ? object->getObjectTemplateName() : "")); + } + + DEBUG_REPORT_LOG(true, ("====[END: container]====\n")); +#endif +} + +//----------------------------------------------------------------------- +bool Container::internalRemoveItem(const Object & item) +{ + + Contents::iterator i = m_contents.begin(); + for(; i != m_contents.end(); ++i) + { + if ((*i) == item.getNetworkId()) + { + (*i) = NetworkId::cms_invalid; + --m_numContents; + return true; + } + } + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Remove an item, identified by an iterator. + * Note that this does not invalidate iterators into the container. + */ +bool Container::remove(ContainerIterator &pos, ContainerErrorCode& error) +{ + error = CEC_Success; + if (*(pos.m_iterator) != NetworkId::cms_invalid) + { + Object *obj = (*(pos.m_iterator)).getObject(); + ContainedByProperty* property = 0; + if (obj) + property = obj->getContainedByProperty(); + WARNING_STRICT_FATAL(!property, ("Cannot remove an item that has no containedby property")); + if (property) + { + if (property->getContainedBy() != &getOwner()) + { + WARNING_STRICT_FATAL(true, ("Cannot remove an item [%s] from container [%s] whose containedBy says it isn't in this container.", (*pos).getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_NotFound; + return false; + } + property->setContainedBy(NetworkId::cms_invalid); + } + + (*pos.m_iterator) = NetworkId::cms_invalid; + --m_numContents; + return true; + } + else + { + error = CEC_Unknown; + return false; + } +} + +//------------------------------------------------------------------------------------------ + +bool Container::mayAdd (const Object& item, ContainerErrorCode& error) const +{ + error = CEC_Success; + if (item.getNetworkId() == getOwner().getNetworkId()) + { + error = CEC_AddSelf; + return false; + } + + if (ConfigSharedObject::getContainerLoopChecking()) + { + //Check that we don't introduce an infinite loop + //First check for container property. Only containers can introduce a loop + const Container* contCheck = item.getContainerProperty(); + if (contCheck) + { + const ContainedByProperty * cbIter = getOwner().getContainedByProperty(); + if (cbIter) + { + NetworkId iterId = cbIter->getContainedByNetworkId(); + if (iterId != NetworkId::cms_invalid) + { + std::vector checkVector; + checkVector.reserve(10); + checkVector.push_back(getOwner().getNetworkId()); + for( int count = 0; iterId != NetworkId::cms_invalid; ++count) + { + if (count > ConfigSharedObject::getContainerMaxDepth()) + { + WARNING(true, ("Too deep a container heirarchy")); + error = CEC_TooDeep; + return false; + } + checkVector.push_back(iterId); + const Object* obj = cbIter->getContainedBy(); + iterId = NetworkId::cms_invalid; + if (obj) + { + cbIter = obj->getContainedByProperty(); + if (cbIter) + { + iterId = cbIter->getContainedByNetworkId(); + } + } + + + } + if (std::find(checkVector.begin(), checkVector.end(), item.getNetworkId()) != checkVector.end()) + { + //detected a loop. + error = CEC_AlreadyIn; + return false; + + } + } + } + + } + } + + if (checkDepth(*this) > ConfigSharedObject::getContainerMaxDepth()) + { + error = CEC_TooDeep; + return false; + } + + if (item.getNetworkId() == getOwner().getNetworkId()) + { + error = CEC_AddSelf; + return false; + } + + return true; +} + +//----------------------------------------------------------------------- +//DO NOT CALL DIRECTLY +int Container::depersistContents(const Object& item) +{ + CachedNetworkId id(item.getNetworkId()); + return insertNewItem(id); +} + + +//----------------------------------------------------------------------- +//DO NOT CALL DIRECTLY +bool Container::internalItemRemoved(const Object& item) +{ + return internalRemoveItem(item); +} + +//----------------------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/container/Container.h b/engine/shared/library/sharedObject/src/shared/container/Container.h new file mode 100644 index 00000000..80178a4b --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/Container.h @@ -0,0 +1,199 @@ +// ====================================================================== +// +// Container.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Container_H +#define INCLUDED_Container_H + +//----------------------------------------------------------------------- + +#include "sharedObject/SlotIdArchive.h" +#include "sharedObject/CachedNetworkId.h" +#include "sharedObject/Property.h" + +namespace Archive +{ + class AutoDeltaByteStream; +} + +class Object; + +//----------------------------------------------------------------------- + +class ContainerIterator +{ + friend class Container; +public: + ContainerIterator(); + ContainerIterator(Container &, const std::vector::iterator &); + ~ContainerIterator(); + ContainerIterator(const ContainerIterator &); + ContainerIterator & operator= (const ContainerIterator &); + + ContainerIterator operator++(int); + ContainerIterator& operator++(); + CachedNetworkId & operator*(); + bool operator==(const ContainerIterator &) const; + bool operator!=(const ContainerIterator &) const; + + +private: + std::vector::iterator m_iterator; + Container * m_owner; +}; + +//----------------------------------------------------------------------- + +class ContainerConstIterator +{ + friend class Container; +public: + ContainerConstIterator(); + ContainerConstIterator(const Container &, const std::vector::const_iterator &); + ~ContainerConstIterator(); + ContainerConstIterator(const ContainerConstIterator &); + ContainerConstIterator & operator= (const ContainerConstIterator &); + + ContainerConstIterator operator++(int); + ContainerConstIterator& operator++(); + const CachedNetworkId & operator*() const; + bool operator==(const ContainerConstIterator &) const; + bool operator!=(const ContainerConstIterator &) const; + + +private: + std::vector::const_iterator m_iterator; + const Container * m_owner; +}; + + +//----------------------------------------------------------------------- + +/** Abstract base class for containers + */ +class Container : public Property +{ +public: + + static PropertyId getClassPropertyId(); + +public: + + typedef CachedNetworkId ContainedItem; + typedef std::vector Contents; + + //Error Codes + enum ContainerErrorCode + { + CEC_Success = 0, + CEC_Unknown, + CEC_AddSelf, + CEC_Full, + CEC_SlotOccupied, + CEC_NoSlot, + CEC_InvalidArrangement, + CEC_WrongType, + CEC_NoPermission, + CEC_OutOfRange, + CEC_NotFound, + CEC_AlreadyIn, + CEC_TooLarge, + CEC_HouseItemLimit, + CEC_TooDeep, + CEC_TryAgain, + CEC_UnmovableType, + CEC_Unmovable, + CEC_CantSee, + CEC_InventoryFull, + CEC_TradeEquipped, + CEC_HopperNotEmpty, + CEC_VirtualContainerUnreachable, + CEC_VirtualContainerUserUnreachable, + CEC_VirtualContainerUserInvalid, + CEC_BlockedByScript, + CEC_BlockedByItemBeingTransferred, + CEC_BlockedBySourceContainer, + CEC_BlockedByDestinationContainer, + CEC_NoContainer, + CEC_SilentError, + CEC_BioLinkedToOtherPlayer, + CEC_Last //This must always be the last errorCode + }; + + + //Iterator + friend class ContainerIterator; + friend class ContainerConstIterator; + + // game interface: + virtual ~Container(void) = 0; + + virtual void addToWorld(); + virtual void removeFromWorld(); + + virtual bool isContentItemObservedWith(Object const &item) const; + virtual bool isContentItemExposedWith(Object const &item) const; + virtual bool canContentsBeObservedWith() const; + + virtual void alter(real time); + virtual void conclude(); + + int getNumberOfItems (void) const; + virtual bool mayAdd (const Object& item, ContainerErrorCode& reason) const = 0; + virtual bool remove (Object &item, ContainerErrorCode& reason) = 0; + virtual bool remove (ContainerIterator &pos, ContainerErrorCode& reason) = 0; + + ContainerIterator begin(); + ContainerIterator end(); + ContainerConstIterator begin() const; + ContainerConstIterator end() const; + + // persistence interface: + // @todo would be nice to protect this somehow. + // but no good way now so DO NOT CALL THESE FUNCTIONS DIRECTLY + virtual int depersistContents(const Object& item); + virtual bool internalItemRemoved(const Object& item); + +public: + bool hasChanged(void) const; + + // debugging functions: + virtual void debugPrint(std::string &buffer) const =0; + virtual void debugLog() const; + +protected: + + /** add an item to the contents. Returns its new position. */ + int addToContents(Object& item, ContainerErrorCode& error); + void clearChanged(void); + + int find (const NetworkId& item, ContainerErrorCode& error) const; + const ContainedItem& getContents (int position) const; + + Container(PropertyId propertyId, Object& owner); + +private: + bool internalRemoveItem(const Object & item); + int insertNewItem(const ContainedItem & item); + /** This function is for use only by this class for debugging. + * You should use the containedBy pointer on the item to check for whether it is contained. + */ + bool isItemContained (const NetworkId& item, ContainerErrorCode & error) const; + + bool m_changed; + Contents m_contents; + int m_numContents; + + Container(); + Container(const Container&); + Container& operator= (const Container&); +}; + +//----------------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.cpp b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.cpp new file mode 100644 index 00000000..b3224648 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.cpp @@ -0,0 +1,134 @@ +// ====================================================================== +// +// SlotDescriptor.cpp +// Copyright 2001 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlotDescriptor.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedObject/SlotDescriptorList.h" +#include "sharedObject/SlotId.h" +#include "sharedObject/SlotIdManager.h" + +#include + +// ====================================================================== + +const Tag TAG_SLTD = TAG(S,L,T,D); + +// ====================================================================== + +SlotDescriptor::SlotDescriptor(Iff &iff, const CrcLowerString &name) +: m_name(new CrcLowerString(name)), + m_slots(new SlotIdVector()), + m_referenceCount(0) +{ + // load object from Iff + iff.enterForm(TAG_SLTD); + + const Tag version = iff.getCurrentName(); + if (version == TAG_0000) + load_0000(iff); + else + { + char buffer[5]; + + ConvertTagToString(version, buffer); + DEBUG_FATAL(true, ("unsupported SlotDescriptor version [%s]\n", buffer)); + } + + iff.exitForm(TAG_SLTD); +} + +// ---------------------------------------------------------------------- + +const CrcLowerString &SlotDescriptor::getName() const +{ + return *m_name; +} + +// ---------------------------------------------------------------------- + +const SlotDescriptor::SlotIdVector &SlotDescriptor::getSlots() const +{ + return *m_slots; +} + +// ---------------------------------------------------------------------- + +void SlotDescriptor::fetch() const +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- + +void SlotDescriptor::release() const +{ + --m_referenceCount; + if (m_referenceCount < 1) + { + // time to delete + + //-- make sure SlotDescriptorList stops tracking this instance + SlotDescriptorList::stopTracking(*this); + + //-- delete the instance + delete const_cast(this); + } +} + +// ---------------------------------------------------------------------- + +int SlotDescriptor::getReferenceCount() const +{ + return m_referenceCount; +} + +// ====================================================================== + +SlotDescriptor::~SlotDescriptor() +{ + // if you get this warning, check if you are trying to delete the + // object when you should be fetch()ing and release()ing. Call + // release() instead. + DEBUG_WARNING(m_referenceCount != 0, ("SlotDescriptor %s destroyed with non-zero reference count [%d]", m_name->getString(), m_referenceCount)); + + delete m_slots; + delete m_name; +} + +// ---------------------------------------------------------------------- + +void SlotDescriptor::load_0000(Iff &iff) +{ + iff.enterForm(TAG_0000); + iff.enterChunk(TAG_DATA); + { + char buffer[1024]; + CrcLowerString slotName(""); + + while (iff.getChunkLengthLeft()) + { + //-- load the slot name + iff.read_string(buffer, sizeof(buffer)-1); + slotName.setString(buffer); + + //-- convert to slot id + const SlotId slotId = SlotIdManager::findSlotId(slotName); + if (slotId == SlotId::invalid) + WARNING(true, ("SlotDescriptor [%s] specified invalid slot [%s], ignoring", m_name->getString(), slotName.getString())); + else + m_slots->push_back(slotId); + } + } + iff.exitChunk(TAG_DATA); + iff.exitForm(TAG_0000); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.h b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.h new file mode 100644 index 00000000..ec9aea34 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptor.h @@ -0,0 +1,74 @@ +// ====================================================================== +// +// SlotDescriptor.h +// Copyright 2001 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlotDescriptor_H +#define INCLUDED_SlotDescriptor_H + +// ====================================================================== + +class CrcLowerString; +class Iff; +class SlotId; + +// ====================================================================== +/** + * Describes a collection of slots. + * + * ObjectTemplate instances that have slotted containers will reference + * a SlotDescriptor instance. The SlotDescriptor instance will list + * the slots available in the slotted container. + * + * This class is a shared resource since (1) both server and client + * need access to this data, (2) we don't want to need to send this + * data around needlessly, and (3) several ObjectTemplate instances + * may reference a single SlotDescriptor instance. For example, + * most (if not all) player species have the same slots available + * for equipping. + */ + +class SlotDescriptor +{ +friend class SlotDescriptorList; + +public: + + typedef stdvector::fwd SlotIdVector; + +public: + + explicit SlotDescriptor(Iff &iff, const CrcLowerString &name); + + const CrcLowerString &getName() const; + const SlotIdVector &getSlots() const; + + void fetch() const; + void release() const; + int getReferenceCount() const; + +private: + + ~SlotDescriptor(); + + void load_0000(Iff &iff); + + // disabled + SlotDescriptor(const SlotDescriptor&); + SlotDescriptor &operator =(const SlotDescriptor&); + +private: + + CrcLowerString *m_name; + SlotIdVector *m_slots; + + mutable int m_referenceCount; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.cpp b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.cpp new file mode 100644 index 00000000..617b4e26 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.cpp @@ -0,0 +1,153 @@ +// ====================================================================== +// +// SlotDescriptorList.cpp +// Copyright 2001 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlotDescriptorList.h" + +#include "sharedDebug/DataLint.h" +#include "sharedFile/Iff.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedObject/SlotDescriptor.h" + +#include +#include + +// ====================================================================== + +bool SlotDescriptorList::ms_installed; +SlotDescriptorList::DescriptorMap *SlotDescriptorList::ms_descriptors; + +// ====================================================================== +// class SlotDescriptorList +// ====================================================================== + +void SlotDescriptorList::install() +{ + DEBUG_FATAL(ms_installed, ("SlotDescriptorList already installed")); + + ms_descriptors = new DescriptorMap(); + + ms_installed = true; + ExitChain::add(remove, "SlotDescriptorList"); +} + +// ---------------------------------------------------------------------- + +const SlotDescriptor *SlotDescriptorList::fetch(const CrcLowerString &filename) +{ + DEBUG_FATAL(!ms_installed, ("SlotDescriptorList not installed")); + + SlotDescriptor *descriptor = 0; + + //-- check if we've got this one cached + DescriptorMap::iterator lowerBoundResult = ms_descriptors->lower_bound(&filename); + if ((lowerBoundResult != ms_descriptors->end()) && !ms_descriptors->key_comp()(&filename, lowerBoundResult->first)) + { + // it's cached, return it + descriptor = lowerBoundResult->second; + } + else + { + // it's not available + + //-- ensure sure file exists + if (!TreeFile::exists(filename.getString())) + { + WARNING(true, ("specified SlotDescriptor file [%s] does not exist", filename.getString())); + return 0; + } + +#ifdef _DEBUG + DataLint::pushAsset(filename.getString()); +#endif // _DEBUG + + //-- load it + Iff iff(filename.getString()); + descriptor = new SlotDescriptor(iff, filename); + +#ifdef _DEBUG + DataLint::popAsset(); +#endif // _DEBUG + + //-- add to managed container + IGNORE_RETURN(ms_descriptors->insert(lowerBoundResult, DescriptorMap::value_type(&descriptor->getName(), descriptor))); + } + + // we should have a valid slot descriptor here + NOT_NULL(descriptor); + + //-- bump up reference count + descriptor->fetch(); + + return descriptor; +} + +// ---------------------------------------------------------------------- +/** + * Return the SlotDescriptor instance contained in the given file. + * + * Prefer the variant of this function taking a CrcLowerString if you + * already have the filename in that format. + */ + +const SlotDescriptor *SlotDescriptorList::fetch(const std::string &filename) +{ + DEBUG_FATAL(!ms_installed, ("SlotDescriptorList not installed")); + + return fetch(CrcLowerString(filename.c_str())); +} + +// ====================================================================== + +void SlotDescriptorList::remove() +{ + DEBUG_FATAL(!ms_installed, ("SlotDescriptorList not installed")); + + //-- handle leaks + if (!ms_descriptors->empty()) + { + DEBUG_WARNING(true, ("SlotDescriptorList: %u named SlotDescriptor leaks", ms_descriptors->size())); + + const DescriptorMap::iterator endIt = ms_descriptors->end(); + for (DescriptorMap::iterator it = ms_descriptors->begin(); it != endIt; ++it) + { + SlotDescriptor *const descriptor = it->second; + + DEBUG_WARNING(descriptor, ("-- leaked SlotDescriptor [%s]", descriptor->getName().getString())); + delete descriptor; + } + } + + delete ms_descriptors; + + ms_installed = false; +} + +// ---------------------------------------------------------------------- + +void SlotDescriptorList::stopTracking(const SlotDescriptor &descriptor) +{ + DEBUG_FATAL(!ms_installed, ("SlotDescriptorList not installed")); + + const CrcLowerString &filename = descriptor.getName(); + + DescriptorMap::iterator lowerBoundResult = ms_descriptors->lower_bound(&filename); + if ((lowerBoundResult == ms_descriptors->end()) || ms_descriptors->key_comp()(&filename, lowerBoundResult->first)) + { + // we don't manage this descriptor + return; + } + + //-- remove the SlotDescriptor from the map + ms_descriptors->erase(lowerBoundResult); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.h b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.h new file mode 100644 index 00000000..68b4d55d --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotDescriptorList.h @@ -0,0 +1,58 @@ +// ====================================================================== +// +// SlotDescriptorList.h +// Copyright 2001 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlotDescriptorList_H +#define INCLUDED_SlotDescriptorList_H + +// ====================================================================== + +class CrcLowerString; +class LessPointerComparator; +class SlotDescriptor; + +// ====================================================================== +/** + * Manages the list of SlotDescriptor objects. + * + * This class provides an interface for creating SlotDescriptor + * objects based on SlotDescriptor files. So long as a single reference exists + * to a SlotDescriptor, that SlotDescriptor will stay loaded and will be returned + * to any caller that asks for it by the same filename. + */ + +class SlotDescriptorList +{ +friend class SlotDescriptor; + +public: + + static void install(); + + static const SlotDescriptor *fetch(const CrcLowerString &filename); + static const SlotDescriptor *fetch(const std::string &filename); + +private: + + typedef stdmap::fwd DescriptorMap; + +private: + + static void remove(); + + static void stopTracking(const SlotDescriptor &descriptor); + +private: + + static bool ms_installed; + static DescriptorMap *ms_descriptors; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotId.cpp b/engine/shared/library/sharedObject/src/shared/container/SlotId.cpp new file mode 100644 index 00000000..fcb51e6b --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotId.cpp @@ -0,0 +1,46 @@ +// ====================================================================== +// +// SlotId.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlotId.h" + +// ====================================================================== + +const SlotId SlotId::invalid(-1); + +// ====================================================================== + +SlotId::SlotId() : + m_slot(-1) +{ +} + +// ---------------------------------------------------------------------- + +SlotId::SlotId(int slot) : + m_slot(slot) +{ +} + +// ---------------------------------------------------------------------- + +SlotId::~SlotId() +{ +} + +// ---------------------------------------------------------------------- + +SlotId& SlotId::operator=(const SlotId& rhs) +{ + if ((&rhs == this) || (rhs == *this)) + return *this; + m_slot = rhs.getSlotId(); + return *this; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotId.h b/engine/shared/library/sharedObject/src/shared/container/SlotId.h new file mode 100644 index 00000000..58df54b0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotId.h @@ -0,0 +1,77 @@ +// ====================================================================== +// +// SlotId.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlotId_H +#define INCLUDED_SlotId_H + +class SlotId +{ +public: + + static const SlotId invalid; + +public: + + SlotId(); + explicit SlotId(int slot); + ~SlotId(); + + int getSlotId() const; + SlotId& operator=(const SlotId&); + bool operator==(const SlotId&) const; + bool operator!=(const SlotId&) const; + bool operator<(const SlotId&) const; + + bool render() const; + +private: + + int m_slot; + +}; + +// ------------------------------------------------------------------------ + +inline int SlotId::getSlotId() const +{ + return m_slot; +} + +// ------------------------------------------------------------------------ + +inline bool SlotId::operator==(const SlotId& rhs) const +{ + return (m_slot == rhs.getSlotId()); +} + +// ------------------------------------------------------------------------ + +inline bool SlotId::operator!=(const SlotId& rhs) const +{ + return !(rhs == *this); +} + +// ------------------------------------------------------------------------ + +inline bool SlotId::operator<(const SlotId& rhs) const +{ + return (m_slot < rhs.getSlotId()); +} + +// ------------------------------------------------------------------------ + +/** Query the slot to find out if we should render its contents. +*/ +inline bool SlotId::render() const +{ + return true; +} + +// ------------------------------------------------------------------------- +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotIdArchive.h b/engine/shared/library/sharedObject/src/shared/container/SlotIdArchive.h new file mode 100644 index 00000000..c1161ed3 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotIdArchive.h @@ -0,0 +1,41 @@ +// SlotIdArchive.h +// copyright 2001 Verant Interactive + +#ifndef _INCLUDED_SlotIdArchive_H +#define _INCLUDED_SlotIdArchive_H + +//----------------------------------------------------------------------- + +#include "Archive/Archive.h" +#include "Archive/ByteStream.h" +#include "sharedObject/SlotId.h" + +//----------------------------------------------------------------------- + +namespace Archive +{ + +//----------------------------------------------------------------------- + + inline void get(ReadIterator & source, SlotId & target) + { + int id; + get(source, id); + target = SlotId(id); + } + +//----------------------------------------------------------------------- + + inline void put(ByteStream & target, const SlotId & source) + { + int tmp = source.getSlotId(); + put(target, tmp); + } + +//----------------------------------------------------------------------- + + +}// namespace Archive +//----------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.cpp b/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.cpp new file mode 100644 index 00000000..9aea59ef --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.cpp @@ -0,0 +1,565 @@ +// ====================================================================== +// +// SlotIdManager.cpp +// Copyright 2001, 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlotIdManager.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedFoundation/PersistentCrcString.h" +#include "sharedFoundation/Tag.h" +#include "sharedObject/SlotId.h" + +#include +#include +#include +#include + +// ====================================================================== + +namespace SlotIdManagerNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Slot + { + public: + + struct LessSlotNameComparator + { + public: + + bool operator ()(const Slot *lhs, const Slot *rhs) const; + bool operator ()(const CrcString *lhs, const Slot *rhs) const; + bool operator ()(const Slot *lhs, const CrcString *rhs) const; + + }; + + public: + + Slot(const char *slotName, bool isPlayerModifiable, bool isAppearanceRelated, char const *hardpointName, uint16 combatBone, bool observeWithParent, bool exposeWithParent); + + CrcString const &getSlotName() const; + bool isPlayerModifiable() const; + bool isAppearanceRelated() const; + CrcString const &getHardpointName() const; + uint16 getCombatBone() const; + bool getObserveWithParent() const; + bool getExposeWithParent() const; + + private: + + // disabled + Slot(); + Slot(const Slot&); //lint -esym(754, Slot::Slot) // defensive hiding + Slot &operator =(const Slot&); //lint -esym(754, Slot::operator=) // defensive hiding + + private: + + PersistentCrcString m_slotName; + bool m_isPlayerModifiable; + bool m_isAppearanceRelated; + PersistentCrcString m_hardpointName; + uint16 m_combatBone; + bool m_observeWithParent; + bool m_exposeWithParent; + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::vector SlotVector; + typedef std::multimap SlotBoneMap; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + bool s_installed; + + SlotVector s_slots; + SlotBoneMap s_slotsSortedByBone; + SlotIdManager::AnythingSlotVector s_slotsThatHoldAnything; +} + +using namespace SlotIdManagerNamespace; + +// ====================================================================== +// class SlotIdManager::Slot +// ====================================================================== + +SlotIdManagerNamespace::Slot::Slot(const char *slotName, bool newIsPlayerModifiable, bool newIsAppearanceRelated, char const *hardpointName, uint16 combatBone, bool observeWithParent, bool exposeWithParent) : + m_slotName(slotName, true), + m_isPlayerModifiable(newIsPlayerModifiable), + m_isAppearanceRelated(newIsAppearanceRelated), + m_hardpointName(hardpointName, true), + m_combatBone(combatBone), + m_observeWithParent(observeWithParent), + m_exposeWithParent(exposeWithParent) +{ +} + +// ---------------------------------------------------------------------- + +inline CrcString const &SlotIdManagerNamespace::Slot::getSlotName() const +{ + return m_slotName; +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::isPlayerModifiable() const +{ + return m_isPlayerModifiable; +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::isAppearanceRelated() const +{ + return m_isAppearanceRelated; +} + +// ---------------------------------------------------------------------- + +inline CrcString const &SlotIdManagerNamespace::Slot::getHardpointName() const +{ + return m_hardpointName; +} + +// ---------------------------------------------------------------------- + +inline uint16 SlotIdManagerNamespace::Slot::getCombatBone() const +{ + return m_combatBone; +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::getObserveWithParent() const +{ + return m_observeWithParent; +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::getExposeWithParent() const +{ + return m_exposeWithParent; +} + +// ====================================================================== +// struct SlotIdManager::Slot::LessSlotNameComparator +// ====================================================================== + +inline bool SlotIdManagerNamespace::Slot::LessSlotNameComparator::operator ()(const Slot *lhs, const Slot *rhs) const +{ + NOT_NULL(lhs); + NOT_NULL(rhs); + return lhs->getSlotName() < rhs->getSlotName(); +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::LessSlotNameComparator::operator ()(const CrcString *lhs, const Slot *rhs) const +{ + NOT_NULL(lhs); + NOT_NULL(rhs); + return *lhs < rhs->getSlotName(); +} + +// ---------------------------------------------------------------------- + +inline bool SlotIdManagerNamespace::Slot::LessSlotNameComparator::operator ()(const Slot *lhs, const CrcString *rhs) const +{ + NOT_NULL(lhs); + NOT_NULL(rhs); + return lhs->getSlotName() < *rhs; +} + +// ====================================================================== +/** + * Install the SlotIdManager. + * + * Clients should specify true for loadHardpointNameData. Servers will + * not need this Appearance-related data loaded. + * + * @param filename The name of the file containing the valid slot data. + * @param loadHardpointNameData If true, hardpoint names associated with slots + * will be loaded. + */ + +void SlotIdManager::install(const std::string &filename, bool loadHardpointNameData) +{ + DEBUG_FATAL(s_installed, ("SlotIdManager already installed")); + + //-- load valid slot names from file + Iff iff(filename.c_str()); + + const Tag version = iff.getCurrentName(); + switch (version) + { + case TAG_0006: + load_0006(iff, loadHardpointNameData); + break; + + default: + { + char buffer[5]; + ConvertTagToString(version, buffer); + FATAL(true, ("unsupported SlotIdManager file format [%s]", buffer)); + } + } + + s_installed = true; + ExitChain::add(remove, "SlotIdManager"); +} + +// ---------------------------------------------------------------------- + +bool SlotIdManager::isInstalled() +{ + return s_installed; +} + +// ---------------------------------------------------------------------- +/** + * Retrieve a SlotId instance for the Slot corresponding to the given + * slot name. + * + * If the specified slot name does not exist, the returned SlotId will be + * equivalent to SlotId::invalid. + * + * @param slotName the name of the slot to lookup. + * + * @return a SlotId instance that may be used in future calls to retrieve + * information regarding the slot. Also used by the SlottedContainer. + */ + +SlotId SlotIdManager::findSlotId(CrcString const &slotName) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + //lint -e18 // error, redeclared template // lint appears to be confused by std::equal_range and its return type + std::pair findResult = std::equal_range(s_slots.begin(), s_slots.end(), &slotName, Slot::LessSlotNameComparator()); //lint !e64 // type mismatch // I think Lint is confused. + if (findResult.first == findResult.second) + { + // return invalid: slot not found. + return SlotId::invalid; + } + else + { + // construct a SlotId from the index of the entry just found. + const int foundIndex = static_cast(std::distance(s_slots.begin(), findResult.first)); + return SlotId(foundIndex); + } +} + +// ---------------------------------------------------------------------- +/** + * Retrieves the slots ids associated with a given combat skeleton bone. + * + * @param bone the combat skeleton bone id + * @param slots vector to be filled in with SlotIds + */ +void SlotIdManager::findSlotIdsForCombatBone(uint32 bone, std::vector & slots) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + SlotBoneMap::const_iterator low = s_slotsSortedByBone.lower_bound(bone); + if (low != s_slotsSortedByBone.end()) + { + SlotBoneMap::const_iterator high = s_slotsSortedByBone.upper_bound(bone); + SlotBoneMap::const_iterator i; + for (i = low; i != high; ++i) + { + slots.push_back(findSlotId((*i).second->getSlotName())); + } + } +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the name of a slot given the slot's SlotId. + * + * @param slotId a SlotId instance for the slot under question. + * + * @return the name of the slot. + */ + +const CrcString &SlotIdManager::getSlotName(const SlotId &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + //-- return a zero-length string for SlotId::invalid. + if (slotId == SlotId::invalid) + return PersistentCrcString::empty; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->getSlotName(); +} +// ---------------------------------------------------------------------- +/** + * Get a list of slots that can hold any item regardless of arrangement. + * Used by SlottedContainmentProperty + * + * @return a vector of SlotIds that hold anything. + */ +const SlotIdManager::AnythingSlotVector& SlotIdManager::getSlotsThatHoldAnything() +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + return s_slotsThatHoldAnything; +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether the given slot is allowed to be modified directly by the + * player. + * + * @param slotId a SlotId instance for the slot under question. + * + * @return true if the player may modify a slot directly, false otherwise. + */ + +bool SlotIdManager::isSlotPlayerModifiable(const SlotId &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + //-- return a zero-length string for SlotId::invalid. + if (slotId == SlotId::invalid) + return false; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->isPlayerModifiable(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether the given slot corresponds to an appearance slot with + * a hardpoint. + * + * If the slot can have something put in it that directly affects what you + * see on the client, this will return true. If this returns false, + * getSlotHardpointName() will return a NULL string. + * + * @param slotId a SlotId instance for the slot under question. + * + * @return true if the given slot corresponds to an appearance slot with + * a hardpoint, false otherwise. + */ + +bool SlotIdManager::isSlotAppearanceRelated(const SlotId &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + //-- return a zero-length string for SlotId::invalid. + if (slotId == SlotId::invalid) + return false; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->isAppearanceRelated(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the name of hardpoint associated with the specified slot. + * + * The caller should check the result of isSlotAppearanceRelated() before + * calling this function. If the slot is not appearance related, this function + * will always return NULL. Also, if the SlotIdManager is installed such that + * hardpoint names are not loaded (currently the server is loaded this way), + * the specified hardpoint name will return NULL. + * + * @param slotId a SlotId instance for the slot under question. + * + * @return the name of the hardpoint associated with the specified slot. + */ + +CrcString const &SlotIdManager::getSlotHardpointName(SlotId const &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + //-- return a zero-length string for SlotId::invalid. + if (slotId == SlotId::invalid) + return PersistentCrcString::empty; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->getHardpointName(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether the slot should have its contents observed when + * the parent is observed. + * + * Here we use observation to mean the concept that a particular object + * is known and visible to a client. + * + * Example usage: the rider slot on a mountable creature is filled with + * the rider when the rider gets on the mount. We need all clients + * that observe the mount (i.e. the parent) to observe the player. + */ + +bool SlotIdManager::getSlotObserveWithParent(const SlotId &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + if (slotId == SlotId::invalid) + return false; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->getObserveWithParent(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve whether the slot should have its contents exposed to the when + * world when the parent is exposed to the world. + * + * Example usage: the rider slot on a mountable creature keeps its rider + * in the world. + */ +bool SlotIdManager::getSlotExposeWithParent(const SlotId &slotId) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + if (slotId == SlotId::invalid) + return false; + + //-- retrieve the specified slot + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, slotId.getSlotId(), static_cast(s_slots.size())); + const Slot *const slot = s_slots[static_cast(slotId.getSlotId())]; + NOT_NULL(slot); + + return slot->getExposeWithParent(); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the number of valid, unique slots supported by the system. + * + * @return the number of valid, unique slots supported by the system. + */ + +int SlotIdManager::getSlotCount() +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + return static_cast(s_slots.size()); +} + +// ---------------------------------------------------------------------- +/** + * Retrieve a SlotId for the specified slot index. + * + * @param index must be in the range 0 .. getSlotCount() - 1, inclusive. + * + * @return a SlotId referencing the index'th slot known to the system. + */ + +SlotId SlotIdManager::getSlotIdByIndex(int index) +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getSlotCount()); + + return SlotId(index); +} + +// ====================================================================== + +void SlotIdManager::remove() +{ + DEBUG_FATAL(!s_installed, ("SlotIdManager not installed")); + + AnythingSlotVector().swap(s_slotsThatHoldAnything); + SlotBoneMap().swap(s_slotsSortedByBone); + + std::for_each(s_slots.begin(), s_slots.end(), PointerDeleter()); + SlotVector().swap(s_slots); +} + +//------------------------------------------------------------------------ + +void SlotIdManager::load_0006(Iff &iff, bool loadHardpointNameData) +{ + //-- load the Slot data + iff.enterForm(TAG_0006); + iff.enterChunk(TAG_DATA); + { + char slotName[512]; + char hardpointName[512]; + + // keep loading entries until done. we don't include count here + // because that would prove error prone for the maintainer of the + // miff data. + while (iff.getChunkLengthLeft()) + { + //-- read the slot name + iff.read_string(slotName, sizeof(slotName) - 1); + slotName[sizeof(slotName) - 1] = '\0'; + + //-- read flags + const bool canAcceptAnyItem = (iff.read_uint8() != 0); + const bool isPlayerModifiable = (iff.read_uint8() != 0); + const bool isAppearanceRelated = (iff.read_uint8() != 0); + + iff.read_string(hardpointName, sizeof(hardpointName) - 1); + hardpointName[sizeof(hardpointName) - 1] = '\0'; + + //-- read the combat skeleton "bone" id + const uint16 combatBone = iff.read_uint16(); + + //-- get the slot's observation characteristics. + bool const observeWithParent = (iff.read_uint8() != 0); + //-- get the slot's world expose characteristics. + bool const exposeWithParent = (iff.read_uint8() != 0); + + //-- construct the slot + Slot * slot = new Slot(slotName, isPlayerModifiable, isAppearanceRelated, loadHardpointNameData ? hardpointName : "", combatBone, observeWithParent, exposeWithParent); + s_slots.push_back(slot); + + if (canAcceptAnyItem) + { + std::string slotString = slotName; + s_slotsThatHoldAnything.push_back(slotString); + } + + //-- add the slot bone list for every bone it's associated with + for (uint16 mask = 0x8000; mask != 0; mask >>= 1) + { + if (mask & combatBone) + IGNORE_RETURN(s_slotsSortedByBone.insert(SlotBoneMap::value_type(mask & combatBone, slot))); + } + } + } + iff.exitChunk(TAG_DATA); + iff.exitForm(TAG_0006); + + //-- sort the Slot data + std::sort(s_slots.begin(), s_slots.end(), Slot::LessSlotNameComparator()); +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.h b/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.h new file mode 100644 index 00000000..e8ce5104 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotIdManager.h @@ -0,0 +1,61 @@ +// ====================================================================== +// +// SlotIdManager.h +// Copyright 2001, 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlotIdManager_H +#define INCLUDED_SlotIdManager_H + +// ====================================================================== + +class CrcString; +class Iff; +class SlotId; + +// ====================================================================== +/** + * The SlotIdManager class maps valid slot names to SlotId objects. + * For clients, it can also provide the Appearance-related hardpoint names + * associated with a given slot. + */ + +class SlotIdManager +{ +public: + + typedef stdvector::fwd AnythingSlotVector; + +public: + + static void install(const std::string &filename, bool loadHardpointNameData); + static bool isInstalled(); + + static SlotId findSlotId(const CrcString &slotName); + static void findSlotIdsForCombatBone(uint32 bone, stdvector::fwd & slots); + + static CrcString const &getSlotName(SlotId const &slotId); + static bool isSlotPlayerModifiable(const SlotId &slotId); + static bool isSlotAppearanceRelated(const SlotId &slotId); + static CrcString const &getSlotHardpointName(SlotId const &slotId); + static bool getSlotObserveWithParent(const SlotId &slotId); + static bool getSlotExposeWithParent(const SlotId &slotId); + + static int getSlotCount(); + static SlotId getSlotIdByIndex(int index); + + static const AnythingSlotVector& getSlotsThatHoldAnything(); + +private: + + static void remove(); + + static void load_0006(Iff &iff, bool loadHardpointNameData); + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/SlotType.def b/engine/shared/library/sharedObject/src/shared/container/SlotType.def new file mode 100644 index 00000000..023dd3d2 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlotType.def @@ -0,0 +1,6 @@ +#ifndef _SLOT_TYPE_DEF +#define _SLOT_TYPE_DEF + +typedef int SlotType; + +#endif \ No newline at end of file diff --git a/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.cpp b/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.cpp new file mode 100644 index 00000000..b97b1a24 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.cpp @@ -0,0 +1,875 @@ +// ====================================================================== +// +// SlottedContainer.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlottedContainer.h" + +#include "sharedFoundation/CrcLowerString.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/Object.h" + +#include +#include + +// ---------------------------------------------------------------------- + +namespace SlottedContainerNamespace +{ + std::vector s_tempIntContainer; +} + +using namespace SlottedContainerNamespace; + +// ------------------------------------------------------------------------ + +SlottedContainer::SlottedContainer(Object& owner, const std::vector& validSlots) : +Container(SlottedContainer::getClassPropertyId(), owner), +m_slotMap(new std::map) +{ + //Inialize the slot list with empty values. + std::vector::const_iterator i = validSlots.begin(); + for (; i != validSlots.end(); ++i) + { + IGNORE_RETURN(m_slotMap->insert(SlotMap::value_type(*i ,-1))); + } +} + +// ------------------------------------------------------------------------ + +SlottedContainer::~SlottedContainer() +{ + if (m_slotMap) + { + delete m_slotMap; + m_slotMap = NULL; + } +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::isContentItemObservedWith(Object const &item) const +{ + //-- Rule 1: if base container claims that the item is visible with the container, + // we stick with that. This prevents us from changing any existing behavior at + // the time this code is written. + bool const observedWithBaseContainer = Container::isContentItemObservedWith(item); + if (observedWithBaseContainer) + return true; + + //-- Rule 2: if the item is in this container, check if any of the current arrangement's + // slots have the observeWithParent attribute set. If so, return true, if not, return false. + ContainedByProperty const *const containedByProperty = item.getContainedByProperty(); + if (!containedByProperty) + return false; + + SlottedContainmentProperty const *const slottedContainmentProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedContainmentProperty) + return false; + int const arrangementIndex = slottedContainmentProperty->getCurrentArrangement(); + + // Note: when checking if item is in container, we must also check + // that contained item's arrangement is set to a valid arrangement. + // This function can be called during container transfers prior to + // the arrangementIndex being set. When this occurs, handle this + // case as if the item is not in the container because it's not really + // there in its entirety yet. + + Object const *const containedByObject = containedByProperty->getContainedBy(); + bool const isInThisContainer = (containedByObject == &getOwner()) && (arrangementIndex >= 0); + + if (isInThisContainer) + { + SlottedContainmentProperty::SlotArrangement const &slots = slottedContainmentProperty->getSlotArrangement(arrangementIndex); + SlottedContainmentProperty::SlotArrangement::const_iterator const endIt = slots.end(); + for (SlottedContainmentProperty::SlotArrangement::const_iterator it = slots.begin(); it != endIt; ++it) + { + bool const observeWithParent = SlotIdManager::getSlotObserveWithParent(*it); + if (observeWithParent) + return true; + } + + return false; + } + + //-- Rule 3: if the item is not in this container, determine which arrangement it would + // use if it went in this slot. If no arrangement is valid, return false. If an arrangement + // is valid, check each slot in the arrangement. If any slot has observeWithParent set true, + // return true; otherwise, return false. + { + ContainerErrorCode errorCode; + int arrangementIndex = -1; + bool const result = getFirstUnoccupiedArrangement(item, arrangementIndex, errorCode); + + if (!result || (errorCode != CEC_Success)) + return false; + + SlottedContainmentProperty::SlotArrangement const &slots = slottedContainmentProperty->getSlotArrangement(arrangementIndex); + SlottedContainmentProperty::SlotArrangement::const_iterator const endIt = slots.end(); + for (SlottedContainmentProperty::SlotArrangement::const_iterator it = slots.begin(); it != endIt; ++it) + { + bool const observeWithParent = SlotIdManager::getSlotObserveWithParent(*it); + if (observeWithParent) + return true; + } + + return false; + } +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::isContentItemExposedWith(Object const &item) const +{ + //-- Rule 1: if base container claims that the item is visible with the container, + // we stick with that. This prevents us from changing any existing behavior at + // the time this code is written. + bool const exposedWithBaseContainer = Container::isContentItemExposedWith(item); + if (exposedWithBaseContainer) + return true; + + //-- Rule 2: if the item is in this container, check if any of the current arrangement's + // slots have the exposeWithParent attribute set. If so, return true, if not, return false. + ContainedByProperty const *const containedByProperty = item.getContainedByProperty(); + if (!containedByProperty) + return false; + + SlottedContainmentProperty const *const slottedContainmentProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedContainmentProperty) + return false; + int const arrangementIndex = slottedContainmentProperty->getCurrentArrangement(); + + // Note: when checking if item is in container, we must also check + // that contained item's arrangement is set to a valid arrangement. + // This function can be called during container transfers prior to + // the arrangementIndex being set. When this occurs, handle this + // case as if the item is not in the container because it's not really + // there in its entirety yet. + + Object const *const containedByObject = containedByProperty->getContainedBy(); + bool const isInThisContainer = (containedByObject == &getOwner()) && (arrangementIndex >= 0); + + if (isInThisContainer) + { + SlottedContainmentProperty::SlotArrangement const &slots = slottedContainmentProperty->getSlotArrangement(arrangementIndex); + SlottedContainmentProperty::SlotArrangement::const_iterator const endIt = slots.end(); + for (SlottedContainmentProperty::SlotArrangement::const_iterator it = slots.begin(); it != endIt; ++it) + { + bool const exposeWithParent = SlotIdManager::getSlotExposeWithParent(*it); + if (exposeWithParent) + return true; + } + + return false; + } + + //-- Rule 3: if the item is not in this container, determine which arrangement it would + // use if it went in this slot. If no arrangement is valid, return false. If an arrangement + // is valid, check each slot in the arrangement. If any slot has exposeWithParent set true, + // return true; otherwise, return false. + { + ContainerErrorCode errorCode; + int arrangementIndex = -1; + bool const result = getFirstUnoccupiedArrangement(item, arrangementIndex, errorCode); + + if (!result || (errorCode != CEC_Success)) + return false; + + SlottedContainmentProperty::SlotArrangement const &slots = slottedContainmentProperty->getSlotArrangement(arrangementIndex); + SlottedContainmentProperty::SlotArrangement::const_iterator const endIt = slots.end(); + for (SlottedContainmentProperty::SlotArrangement::const_iterator it = slots.begin(); it != endIt; ++it) + { + bool const exposeWithParent = SlotIdManager::getSlotExposeWithParent(*it); + if (exposeWithParent) + return true; + } + + return false; + } +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::canContentsBeObservedWith() const +{ + // Content items can be observed with this container if any of our slots are marked for observe with parent. + for (SlotMap::const_iterator i = m_slotMap->begin(); i != m_slotMap->end(); ++i) + if (SlotIdManager::getSlotObserveWithParent((*i).first)) + return true; + return false; +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::add (Object& item, int arrangementIndex, ContainerErrorCode & error) +{ + error = CEC_Success; + if (arrangementIndex < 0) + { + error = CEC_InvalidArrangement; + return false; + } + + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedProperty) + { + WARNING_STRICT_FATAL(true, ("Tried to add an item %s to a slot container with no slotted property. Make sure its shared object template has a valid arrangement", item.getNetworkId().getValueString().c_str())); + error = CEC_Unknown; + return false; + } + + if (!internalCheckSlottedAdd (item, arrangementIndex, error)) + return false; + + int position = addToContents(item, error); + if (position < 0) + return false; + + if (!internalDoSlottedAdd(item, position, arrangementIndex)) + { + WARNING_STRICT_FATAL(true, ("internal Check add worked, but trying to do it failed.")); + error = CEC_Unknown; + return false; + } + slottedProperty->setCurrentArrangement(arrangementIndex); + return true; + +} +// ------------------------------------------------------------------------ + +bool SlottedContainer::add (Object& item, const SlotId & slotId, ContainerErrorCode& error) +{ + error = CEC_Success; + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedProperty) + { + WARNING_STRICT_FATAL(true, ("Tried to add an item %s to a slot container with no slotted property Make sure its shared object template has a valid arrangement ", item.getNetworkId().getValueString().c_str())); + error = CEC_Unknown; + return false; + } + + return add(item, slottedProperty->getBestArrangementForSlot(slotId), error); +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::internalCheckSlottedAdd( Object& item, int arrangementIndex, ContainerErrorCode & error ) const +{ + error = CEC_Success; + if (arrangementIndex < 0) + { + error = CEC_InvalidArrangement; + return false; + } + + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedProperty) + { + WARNING_STRICT_FATAL(true, ("Tried to add an item %s to a slot container with no slotted property Make sure its shared object template has a valid arrangement", item.getNetworkId().getValueString().c_str())); + error = CEC_Unknown; + return false; + } + + // realize that this is a 2*O(1) search, once for the mayAdd, the once for the fill. + if (!mayAdd(item, arrangementIndex, error)) + return false; + + return true; +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::internalDoSlottedAdd( Object& item, int position, int arrangementIndex ) +{ + if (arrangementIndex < 0) + return false; + + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + // get the arrangement from the item with arrangementIndex + const int numSlots = slottedProperty->getNumberOfSlots(arrangementIndex); + // fill each slot in the list with our own slot map + for (int i = 0; i < numSlots; ++i) + { + SlotMap::iterator j = m_slotMap->find(slottedProperty->getSlotId(arrangementIndex, i)); + if (j != m_slotMap->end() && j->second == -1) + { + j->second = position; + } + else + WARNING_STRICT_FATAL(true, ("We're trying to add an item to a slotted container that does not have a slot that this item %s with this arrangment %d can go into or has something in it already.", item.getNetworkId().getValueString().c_str(), arrangementIndex)); + } + return true; +} + +// ------------------------------------------------------------------------ + +int SlottedContainer::find(const SlotId &slot) const +{ + SlotMap::const_iterator i = m_slotMap->find(slot); + if (i == m_slotMap->end()) //lint !e1702 STL operator== both a member and not + { + DEBUG_WARNING(true, ("Tried to find from an invalid slot on this container [%s]. Check the container's slot descriptor file to make sure it has slot %s.", getOwner().getNetworkId().getValueString().c_str(), SlotIdManager::getSlotName(slot).getString() )); + return -1; + } + + return i->second; //lint !e1702 STL operator== both a member and not +} + +// ------------------------------------------------------------------------ + +Container::ContainedItem SlottedContainer::getObjectInSlot (const SlotId &slot, ContainerErrorCode & error) +{ + error = CEC_Success; + if (!hasSlot(slot)) + { + error = CEC_NoSlot; + return CachedNetworkId::cms_cachedInvalid; + } + + int position = find(slot); + if (position < 0) + { + error = CEC_NotFound; + return CachedNetworkId::cms_cachedInvalid; + } + + return getContents(position); +} //lint !e1762 // function could be made const // yes, but we don't want you to modify contents of a const container + +// ------------------------------------------------------------------------ + +const Container::ContainedItem SlottedContainer::getObjectInSlot (const SlotId &slot, ContainerErrorCode & error) const +{ + error = CEC_Success; + //@todo I must not be doing this right...I should be sharing code with the above routine. + if (!hasSlot(slot)) + { + error = CEC_NoSlot; + return CachedNetworkId::cms_cachedInvalid; + } + + int position = find(slot); + if (position < 0) + { + error = CEC_NotFound; + return CachedNetworkId::cms_cachedInvalid; + } + + return getContents(position); +} + +// ------------------------------------------------------------------------ + +/** + * Retrieves all the objects in slots associated with a combat bone. + * + * @param bone the combat bone id + * @param objects list that will be filled with the objects in the slots + */ +void SlottedContainer::getObjectsForCombatBone(uint32 bone, + std::vector & objects) const +{ + std::vector slots; + SlotIdManager::findSlotIdsForCombatBone(bone, slots); + std::vector::const_iterator iter; + ContainerErrorCode tmp = CEC_Success; + for (iter = slots.begin(); iter != slots.end(); ++iter) + { + Container::ContainedItem item = getObjectInSlot(*iter, tmp); + if (item != NetworkId::cms_invalid) + objects.push_back(item); + } +} + +// ------------------------------------------------------------------------ + +PropertyId SlottedContainer::getClassPropertyId() +{ + return PROPERTY_HASH(SlottedContainer, 0x7ED71F2E); +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::getFirstUnoccupiedArrangement(const Object &item, int& arrangementIndex, ContainerErrorCode& error) const +{ + error = CEC_Success; + arrangementIndex = -1; + + //-- get list of valid arrangements + std::vector tmp; + getValidArrangements(item, tmp, error, true, true); + + bool result = false; + + if (tmp.empty()) + { + result = false; + } + else + { + arrangementIndex = tmp.front(); + result = true; + } + + return result; +} + +// ------------------------------------------------------------------------ +/** + * Return a list of valid arrangement indices for the item in this container. + * + * @todo Modify getValidArrangements to take an argument that checks for unoccupied arrangements. + */ + +void SlottedContainer::getValidArrangements(const Object& item, std::vector& returnList, ContainerErrorCode& error, bool returnOnFirst, bool unoccupiedArrangementsOnly) const +{ + error = CEC_Success; + returnList.clear(); + + const SlottedContainmentProperty* slottedContainment = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedContainment) + { + error = CEC_WrongType; + return; + } + + //@todo revisit slotted properties to use iterators + int numArrangements = slottedContainment->getNumberOfArrangements(); + + //For each arrangement, check ourself to see if each slot in that arrangement exists. + //As soon as we find an arrangement that has all of our slots, we can return that arrangement index + for (int i = 0; i < numArrangements; ++i) + { + const int numSlots = slottedContainment->getNumberOfSlots(i); + int availableSlots = 0; + bool slotPresent = true; + + for (int j = 0; j < numSlots; ++j) + { + SlotId slot = slottedContainment->getSlotId(i,j); + + // check if slot is present in this container + if (!hasSlot(slot)) + { + //A slot is not present, flag for next loop and break to the next loop + slotPresent = false; + break; + } + + // check if slot is available + if (unoccupiedArrangementsOnly && isSlotEmpty(slot, error)) + ++availableSlots; + } + //If we haven't been flagged above then we found a valid arrangement + if (slotPresent) + { + // check if we're ignoring unoccupied slots or if all slots were unoccupied + if (!unoccupiedArrangementsOnly || (availableSlots == numSlots)) + { + returnList.push_back(i); + if (returnOnFirst) + return; + } + } + } + + //We found no arrangements on the item that only contains slot ids that we have. + error = CEC_SlotOccupied; + return; +} + +// ------------------------------------------------------------------------ +/** + * Append the contents of the slotted container to the specified buffer. + * + * @param buffer the string that will have debug information appended to it on return. + */ + +void SlottedContainer::debugPrint(std::string &buffer) const +{ + char tempBuffer[1024]; + + buffer += "====[BEGIN: slotted container]====\n"; + + //-- List supported slots and container indices. + sprintf(tempBuffer, "container id [%s]: contains [%d] slots.\n", getOwner().getNetworkId().getValueString().c_str(), static_cast(m_slotMap->size())); + buffer += tempBuffer; + + SlotMap::const_iterator const endIt = m_slotMap->end(); + for (SlotMap::const_iterator it = m_slotMap->begin(); it != endIt; ++it) + { + sprintf(tempBuffer, "\tslot [%3d, %20s]: index [%3d]\n", it->first.getSlotId(), SlotIdManager::getSlotName(it->first).getString(), it->second); + buffer += tempBuffer; + } + + buffer += "embedding container contents now:\n"; + Container::debugPrint(buffer); + + buffer += "====[END: slotted container]====\n"; +} + +// ---------------------------------------------------------------------- + +void SlottedContainer::debugLog() const +{ +#ifdef _DEBUG + DEBUG_REPORT_LOG(true, ("====[BEGIN: slotted container]====\n")); + + //-- List supported slots and container indices. + DEBUG_REPORT_LOG(true, ("container id [%s]: contains [%d] slots.\n", getOwner().getNetworkId().getValueString().c_str(), static_cast(m_slotMap->size()))); + + SlotMap::const_iterator const endIt = m_slotMap->end(); + for (SlotMap::const_iterator it = m_slotMap->begin(); it != endIt; ++it) + { + DEBUG_REPORT_LOG(true, ("\tslot [%20s]: index [%3d]\n", SlotIdManager::getSlotName(it->first).getString(), it->second)); + } + + DEBUG_REPORT_LOG(true, ("Embedding container contents now:\n")); + Container::debugLog(); + + DEBUG_REPORT_LOG(true, ("====[END: slotted container]====\n")); +#endif +} + +// -------------------------------------------------------------------------------- + +bool SlottedContainer::hasSlot (const SlotId &slot) const +{ + SlotMap::const_iterator i = m_slotMap->find(slot); + if (i == m_slotMap->end()) //lint !e1702 STL operator== both a member and not + return false; + return true; +} + +// -------------------------------------------------------------------------------- + +/** + * Returns the slot ids for this container. + * + * @param slots list that will be filled in with the slot ids + */ +void SlottedContainer::getSlotIdList(std::vector & slots) const +{ + SlotMap::const_iterator iter; + for (iter = m_slotMap->begin(); iter != m_slotMap->end(); ++iter) + { + if ((*iter).first != SlotId::invalid) + slots.push_back(iter->first); + } +} + +// ---------------------------------------------------------------------- + +bool SlottedContainer::isSlotEmpty (const SlotId &slot, ContainerErrorCode& error) const +{ + error = CEC_Success; + // find slot data + if (!hasSlot(slot)) + { + error = CEC_NoSlot; + return false; + } + + bool retval = (find(slot) == -1); + if (!retval) + error = CEC_SlotOccupied; + return retval; +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::mayAdd(const Object& item, ContainerErrorCode& error) const +{ + error = CEC_Success; + //@todo This is an inefficient function. getValidArrangements and mayAdd(object, int) both do a lot of searching that is redundant. + + s_tempIntContainer.clear(); + getValidArrangements(item, s_tempIntContainer, error); + + std::vector::iterator const endIt = s_tempIntContainer.end(); + for(std::vector::iterator i = s_tempIntContainer.begin(); i != endIt; ++i) + { + if (mayAdd(item, (*i), error)) + return true; + } + return false; +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::mayAdd(const Object& item, int arrangementIndex, ContainerErrorCode& error) const +{ + error = CEC_Success; + if (arrangementIndex < 0) + { + error = CEC_InvalidArrangement; + return false; + } + + if (item.getNetworkId() == getOwner().getNetworkId()) + { + error = CEC_AddSelf; + return false; + } + + const SlottedContainmentProperty* slottedContainment = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedContainment) + { + WARNING_STRICT_FATAL(true, ("Tried to check slots with an item with no slotted containement property.")); + error = CEC_Unknown; + return false; + } + + int numSlots = slottedContainment->getNumberOfSlots(arrangementIndex); + for (int j = 0; j < numSlots; ++j) + { + SlotId slot = slottedContainment->getSlotId(arrangementIndex,j); + if (!isSlotEmpty(slot, error)) + { + //A slot does not exist or is occupied in the arrangement already. + return false; + } + } + return Container::mayAdd(item, error); +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::mayAdd(const Object& item, const SlotId& slotId, ContainerErrorCode& error) const +{ + error = CEC_Success; + if (!isSlotEmpty(slotId, error)) + { + return false; + } + + const SlottedContainmentProperty* slottedContainment = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedContainment) + { + WARNING_STRICT_FATAL(true, ("Tried to check slots with an item with no slotted containement property.")); + error = CEC_Unknown; + return false; + } + return mayAdd(item, slottedContainment->getBestArrangementForSlot(slotId), error); + +} + + +// ------------------------------------------------------------------------ + +bool SlottedContainer::internalRemove(const Object& item, int overrideArrangement) +{ + ContainerErrorCode tmp = CEC_Success; + UNREF(overrideArrangement); + //Check for the item's position in contents + int position = Container::find(item.getNetworkId(), tmp); + if (position == -1) + { + WARNING_STRICT_FATAL(true, ("SlottedContainer::internalRemove() called with an invalid item: container owner id=[%s], template=[%s]; item id=[%s], template=[%s]", + getOwner().getNetworkId().getValueString().c_str(), getOwner().getObjectTemplateName(), + item.getNetworkId().getValueString().c_str(), item.getObjectTemplateName())); + return false; + } + + //Clean up the slot map + SlotMap::iterator i = m_slotMap->begin(); + for(;i != m_slotMap->end(); ++i) //lint !e1702 STL operator== both a member and not + { + if(i->second == position) //lint !e1702 STL operator== both a member and not + { + i->second = -1; + } + } + return true; +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::remove(Object& item, ContainerErrorCode& error) +{ + error = CEC_Success; + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedProperty) + { + WARNING_STRICT_FATAL(true, ("Tried to remove an item %s to a slot container with no slotted property", item.getNetworkId().getValueString().c_str())); + error = CEC_Unknown; + return false; + } + + //Check for the item's position in contents + int position = Container::find(item.getNetworkId(), error); + if (position == -1) + { + DEBUG_WARNING(true, ("Called SlottedContainer::remove() with item [%s] from container [%s], but the item was not found in the base container's contents. This means the item was not in the container.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + error = CEC_NotFound; + return false; + } + + //Try to remove it from contents + if (!internalRemove(item)) + { + error = CEC_Unknown; + return false; + } + + if (!Container::remove(item, error)) + { + return false; + } + + slottedProperty->setCurrentArrangement(-1); + return true; +} + +// ---------------------------------------------------------------------- + +bool SlottedContainer::remove(ContainerIterator &pos, ContainerErrorCode& error) +{ + error = CEC_Success; + Object *obj=(*pos).getObject(); + if (obj) + return remove(*obj, error); + else + { + error = CEC_Unknown; + return false; + } +} + +// ------------------------------------------------------------------------ + +void SlottedContainer::removeItemFromSlotOnly(const Object &item) +{ + IGNORE_RETURN(internalRemove(item)); +} + +// ------------------------------------------------------------------------ + +int SlottedContainer::depersistContents(Object&) +{ + WARNING_STRICT_FATAL(true, ("Do not use this interface. Use interface with arrangement instead.")); + return -1; +} + +// ------------------------------------------------------------------------ + +void SlottedContainer::depersistSlotContents(Object& item, int arrangementIndex) +{ + ContainerErrorCode tmp = CEC_Success; + SlottedContainmentProperty * slottedProperty = safe_cast(item.getProperty(SlottedContainmentProperty::getClassPropertyId())); + if (!slottedProperty) + { + WARNING_STRICT_FATAL(true, ("Tried to add an item %s to a slot container with no slotted property\n", item.getNetworkId().getValueString().c_str())); + return; + } + +//Special case...when depersisting an object its to have arrangmentIndex = -1 for baselines + if (arrangementIndex < 0) + { + int tmp2 = Container::depersistContents(item); + UNREF(tmp2); + return; + } + + + //Make sure we can depersist into the arrangement we had last saved. + if (!internalCheckSlottedAdd(item, arrangementIndex, tmp)) + { + //if not try to find a valid one to depersist to. + int arrangement = -1; + DEBUG_WARNING(true, ("Could not depersist item [%s] into container [%s] with arrangement %d, ContainerErrorCode=%d. This is typically bad, and may result in the item being in an invalid state or even moved to 0 0 0 in the world. We will now attempt to find a different arrangement to depersist this item with.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str(), arrangementIndex, static_cast(tmp))); + if (!getFirstUnoccupiedArrangement(item, arrangement, tmp)) + { + //warning/fatal if we can't find a valid arrangement + WARNING_STRICT_FATAL(true, ("Could not depersist item [%s] into container [%s] because there was no good arrangement, ContainerErrorCode=%d. See previous warning. We then attempted to find a different arrangement to put the item into, because the item really belongs in this container, but could not because it was either already occupied or the arrangement of the item was changed so that it cannot be placed in this container anymore. This is typically bad, and may result in the item being in an invalid state or even moved to 0 0 0 in the world. This might happen because the arrangement file was changed for this object and existing objects could no longer be persisted into their containers.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str(), static_cast(tmp))); + } + else + { + int position = Container::depersistContents(item); + if (position >= 0 && internalDoSlottedAdd(item, position, arrangement)) + { + //change the current arrangement to the new one we found + slottedProperty->setCurrentArrangement(arrangement); + } + else + { + WARNING_STRICT_FATAL(true, ("Could not depersist item [%s] into container [%s] because add item failed. We found a good different arrangement to add the item to, but the base container prevented the transfer.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + } + } + } + + //It's ok to depersist into the arrangement we were saved with. + else + { + int position = Container::depersistContents(item); + + + if (arrangementIndex >= 0 && !internalDoSlottedAdd(item, position, arrangementIndex)) + { + WARNING_STRICT_FATAL(true, ("Could not depersist item [%s] into container [%s] because add item failed. For some reason the base container prevented the transfer.", item.getNetworkId().getValueString().c_str(), getOwner().getNetworkId().getValueString().c_str())); + } + } +} + +// ------------------------------------------------------------------------ + +bool SlottedContainer::internalItemRemoved(const Object& item) +{ + if (internalRemove(item)) + { + return Container::internalItemRemoved(item); + } + + return false; +} + +// ------------------------------------------------------------------------ + +void SlottedContainer::updateArrangement(Object& item, int oldArrangement, int newArrangement) +{ + ContainerErrorCode tmp = CEC_Success; + if (!internalRemove(item, oldArrangement)) + { + DEBUG_WARNING(true, ("Remove part of update failed in slotted container")); + } + + int position = Container::find(item.getNetworkId(), tmp); + if (position < 0) + { + DEBUG_WARNING(true, ("could not find object in update slotted container")); + } + else if (newArrangement >= 0 && !internalDoSlottedAdd(item, position, newArrangement)) + { + DEBUG_WARNING(true, ("updating slotted container failed")); + } + +} + +//---------------------------------------------------------------------- + +const SlotId & SlottedContainer::findFirstSlotIdForObject (const NetworkId & id) const +{ + Container::ContainerErrorCode tmp = Container::CEC_Success; + const int position = Container::find (id, tmp); + if (position >= 0) + { + for (SlottedContainer::SlotMap::const_iterator sit = m_slotMap->begin(); sit != m_slotMap->end(); ++sit) + { + const int objPosition = (*sit).second; + + if (objPosition == position) + return (*sit).first; + } + } + + return SlotId::invalid; +} + +// ------------------------------------------------------------------------ diff --git a/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.h b/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.h new file mode 100644 index 00000000..59683f01 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlottedContainer.h @@ -0,0 +1,92 @@ +// ====================================================================== +// +// SlottedContainer.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlottedContainer_H +#define INCLUDED_SlottedContainer_H + +// ====================================================================== + +#include "sharedObject/Container.h" + +// ====================================================================== + +class SlottedContainer : public Container +{ +public: + + static PropertyId getClassPropertyId(); + +public: + + SlottedContainer(Object& owner, const std::vector& validSlots); + ~SlottedContainer(); + + virtual bool isContentItemObservedWith(Object const &item) const; + virtual bool isContentItemExposedWith(Object const &item) const; + virtual bool canContentsBeObservedWith() const; + + bool add (Object& item, int arrangementIndex, ContainerErrorCode& error); + bool add (Object& item, const SlotId & slotId, ContainerErrorCode& error); + Container::ContainedItem getObjectInSlot (const SlotId &slot, ContainerErrorCode& error); + const Container::ContainedItem getObjectInSlot (const SlotId &slot, ContainerErrorCode& error) const; + void getObjectsForCombatBone(uint32 bone, std::vector & objects) const; + + bool getFirstUnoccupiedArrangement(const Object& item, int& arrangementIndex, ContainerErrorCode& error) const; + void getValidArrangements(const Object& item, std::vector& returnList, ContainerErrorCode & error, bool returnOnFirst = false, bool unoccupiedArrangementsOnly = false) const; + bool hasSlot (const SlotId &slot) const; + bool isSlotEmpty (const SlotId &slot, ContainerErrorCode& error) const; + + virtual void debugPrint(std::string &buffer) const; + virtual void debugLog() const; + + virtual bool mayAdd(const Object& item, ContainerErrorCode& error) const; + bool mayAdd(const Object& item, int arrangementIndex, ContainerErrorCode& error) const; + bool mayAdd(const Object& item, const SlotId & slotId, ContainerErrorCode& error) const; + virtual bool remove(Object &item, ContainerErrorCode& error); + virtual bool remove(ContainerIterator &pos, ContainerErrorCode& error); + void removeItemFromSlotOnly(const Object &item); + + void getSlotIdList(std::vector & slots) const; + + const SlotId & findFirstSlotIdForObject (const NetworkId & id) const; + + //might need an addSlot() interface for the loader + + //persistance interface. Do not call directly. + virtual int depersistContents(Object& item); + void depersistSlotContents(Object& item, int arrangement); + virtual bool internalItemRemoved(const Object& item); + void updateArrangement(Object& item, int oldArrangement, int newArrangement); + +private: + + typedef stdmap::fwd SlotMap; + +private: + + /** shortened find on the map. Returns -1 if not found. + */ + int find(const SlotId &slot) const; + + bool internalCheckSlottedAdd( Object& item, int arrangementIndex, ContainerErrorCode& error ) const; + bool internalDoSlottedAdd( Object& item, int position, int arrangementIndex ); + bool internalRemove(const Object& item, int overrideArrangement = -1); + + /** This is the map of slot ids to contents. It is initialized with -1 values. + * Anything greater than or equal to 0 indicates a position in the contents list. + */ + SlotMap *m_slotMap; + + SlottedContainer(); + SlottedContainer(const SlottedContainer&); + SlottedContainer& operator= (const SlottedContainer&); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.cpp b/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.cpp new file mode 100644 index 00000000..b3d304f4 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.cpp @@ -0,0 +1,243 @@ +// ====================================================================== +// +// SlottedContainmentProperty.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SlottedContainmentProperty.h" + +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Object.h" +#include "sharedObject/SlotId.h" +#include "sharedObject/SlotIdManager.h" +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(SlottedContainmentProperty, true, 0, 0, 0); + +// ====================================================================== + +SlottedContainmentProperty::SlottedContainmentProperty(Object& owner) : +Property(SlottedContainmentProperty::getClassPropertyId(), owner), +m_arrangementList(), +m_currentArrangement(-1) +{ + //Add slots that can hold anything + SlotIdManager::AnythingSlotVector anythingSlots = SlotIdManager::getSlotsThatHoldAnything(); + for (SlotIdManager::AnythingSlotVector::iterator i = anythingSlots.begin(); i != anythingSlots.end(); ++i) + { + SlotArrangement tmp; + CrcLowerString tmp2(i->c_str()); + SlotId slotId = SlotIdManager::findSlotId(tmp2); + tmp.push_back(slotId); + addArrangement(tmp); + } +} + +// --------------------------------------------------------------------- + + +SlottedContainmentProperty::~SlottedContainmentProperty() +{ + +} + +// --------------------------------------------------------------------- + +void SlottedContainmentProperty::addArrangement(const SlotArrangement &arrangement) +{ + if (arrangement.size() >= SCP_MaxArrangementSize) + { + WARNING_STRICT_FATAL(true, ("Cannot add this arrangement. It is too big.")); + return; + } + m_arrangementList.push_back(arrangement); +} + +// --------------------------------------------------------------------- + +bool SlottedContainmentProperty::canManipulateArrangement(int arrangementIndex) const +{ + if (arrangementIndex < 0) + { + WARNING_STRICT_FATAL(true, ("Passed -1 to canManipulateArrangement")); + return true; + } + + int numArrangements = getNumberOfArrangements(); + if (numArrangements == 0) + return false; + if (arrangementIndex >= numArrangements) + { + const Object& owner = getOwner(); + WARNING_STRICT_FATAL(true, ("Tried to pass an invalid arrangement index %d for object %s", arrangementIndex, owner.getNetworkId().getValueString().c_str())); + return false; + } + + std::vector::const_iterator i = m_arrangementList[static_cast(arrangementIndex)].begin(); + for (;i != m_arrangementList[static_cast(arrangementIndex)].end(); ++i) + { + if (!SlotIdManager::isSlotPlayerModifiable(*i)) + return false; + } + return true; +} + + +// --------------------------------------------------------------------- + +/** +* This function returns the "best" arrangement that has a given slotId. +* The best arrangement is the one that has the given slotId nearest to the front of +* the slot list. +*/ +int SlottedContainmentProperty::getBestArrangementForSlot(const SlotId & slotId) const +{ + //@todo Make sure arrangements are added in data in the correct order to ensure "bestness" + int bestValue = SCP_MaxArrangementSize; + int bestArrangement = -1; + + int arrangementIndex = 0; + for (ArrangementList::const_iterator i = m_arrangementList.begin(); i != m_arrangementList.end(); ++i, ++arrangementIndex) + { + int slotIndex = 0; + for (SlotArrangement::const_iterator j = i->begin(); j != i->end(); ++j, ++slotIndex) + { + if (slotId == *j && slotIndex < bestValue) + { + bestValue = slotIndex; + bestArrangement = arrangementIndex; + break; + } + } + + // quick test to see if we can stop iterating. + if (bestValue == 0) + break; + } + + return bestArrangement; +} + +// --------------------------------------------------------------------- + +int SlottedContainmentProperty::getNumberOfArrangements () const +{ + return static_cast(m_arrangementList.size()); +} + +// --------------------------------------------------------------------- + +int SlottedContainmentProperty::getNumberOfSlots (int arrangementIndex) const +{ + int numArrangements = getNumberOfArrangements(); + if (numArrangements == 0) + return 0; + if (arrangementIndex < 0 || arrangementIndex >= numArrangements) + { + WARNING_STRICT_FATAL(true, ("Tried to pass an invalid arrangement index to this slotted container")); + return 0; + } + return static_cast(m_arrangementList[static_cast(arrangementIndex)].size()); +} + +// --------------------------------------------------------------------- + +PropertyId SlottedContainmentProperty::getClassPropertyId() +{ + return PROPERTY_HASH(SlottedContainment, 0xED3067A9); +} + +// ----------------------------------------------------------- + +const SlottedContainmentProperty::SlotArrangement & SlottedContainmentProperty::getSlotArrangement(int arrangementIndex) const +{ + if (arrangementIndex < 0 || arrangementIndex >= getNumberOfArrangements()) + { + WARNING_STRICT_FATAL(true, ("Tried to pass an invalid arrangement index to getSlotArrangement")); + return m_arrangementList[0]; + } + return m_arrangementList[static_cast(arrangementIndex)]; +} + + +// ----------------------------------------------------------- + +SlotId SlottedContainmentProperty::getSlotId (int arrangementIndex, int slotIndex) const +{ + if (arrangementIndex < 0) + { + WARNING_STRICT_FATAL(true, ("Tried to pass a negative arrangement index [%d] to this slotted container", arrangementIndex)); + return SlotId::invalid; + } + + if (slotIndex < 0) + { + WARNING_STRICT_FATAL(true, ("Tried to pass a negative slotIndex [%d] to this slotted container", slotIndex)); + return SlotId::invalid; + } + + int num = getNumberOfArrangements(); + if (num == 0) + return SlotId::invalid; + if (num < arrangementIndex) + { + WARNING_STRICT_FATAL(true, ("Tried to pass an invalid arrangement index to this slotted container")); + return SlotId::invalid; + } + + num = getNumberOfSlots(arrangementIndex); + if (num == 0) + return SlotId::invalid; + if (num < slotIndex) + { + WARNING_STRICT_FATAL(true, ("Tried to pass an invalid slot index to this slotted container")); + return SlotId::invalid; + } + + return m_arrangementList[static_cast(arrangementIndex)][static_cast(slotIndex)]; +} + +// --------------------------------------------------------------------- + +bool SlottedContainmentProperty::isInAppearanceSlot() const +{ + int arrangement = getCurrentArrangement(); + int numSlots = getNumberOfSlots(arrangement); + for (int i = 0; i < numSlots; ++i) + { + SlotId id = getSlotId(arrangement, i); + if (SlotIdManager::isSlotAppearanceRelated(id)) + return true; + } + return false; +} + +// --------------------------------------------------------------------- + +int SlottedContainmentProperty::getCurrentArrangement() const +{ + return m_currentArrangement; +} + +// ------------------------------------------------------------------------ + +void SlottedContainmentProperty::setCurrentArrangement(int arrangement, bool local) +{ + if (m_currentArrangement != arrangement) + { + int oldValue = m_currentArrangement; + m_currentArrangement = arrangement; + getOwner().arrangementModified(oldValue, arrangement, local); + } +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.h b/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.h new file mode 100644 index 00000000..fb1c9347 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/SlottedContainmentProperty.h @@ -0,0 +1,73 @@ +// ====================================================================== +// +// SlottedContainmentProperty.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_SlottedContainmentProperty_H +#define INCLUDED_SlottedContainmentProperty_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/Property.h" +#include + +// ====================================================================== + +class SlotId; + +// ====================================================================== + +class SlottedContainmentProperty : public Property +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + static PropertyId getClassPropertyId(); + + enum + { + SCP_MaxArrangementSize = 0xFFF + }; + + typedef std::vector SlotArrangement; + typedef std::vector ArrangementList; + //revisit possibly using iterators + +public: + explicit SlottedContainmentProperty(Object& owner); + ~SlottedContainmentProperty(); + + void addArrangement(const SlotArrangement &arrangement); + + bool canManipulateArrangement(int arrangementIndex) const; + + int getBestArrangementForSlot(const SlotId & slotId) const; + int getCurrentArrangement() const; + int getNumberOfArrangements () const; + int getNumberOfSlots (int arrangementIndex) const; + + const SlotArrangement & getSlotArrangement(int arrangementIndex) const; + + SlotId getSlotId (int arrangementIndex, int slotIndex) const; + + bool isInAppearanceSlot() const; + void setCurrentArrangement(int arrangement, bool local = true); + +private: + ArrangementList m_arrangementList; //This could also be with the object template! Definately not persisted + int m_currentArrangement; + + SlottedContainmentProperty(); + SlottedContainmentProperty(const SlottedContainmentProperty&); + SlottedContainmentProperty& operator= (const SlottedContainmentProperty&); +}; + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.cpp b/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.cpp new file mode 100644 index 00000000..b3154084 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.cpp @@ -0,0 +1,480 @@ +// ====================================================================== +// +// VolumeContainer.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/VolumeContainer.h" + +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Object.h" +#include "sharedObject/VolumeContainmentProperty.h" +#include "sharedObject/ObjectTemplate.h" + +#include "sharedFoundation/CrcLowerString.h" + +#include + +//----------------------------------------------------------------------- + +namespace VolumeContainerNamespace +{ + VolumeContainer* getVolumeContainerParent(VolumeContainer& self) + { + Object & owner = self.getOwner (); + ContainedByProperty * containedByProperty = owner.getContainedByProperty (); + if (containedByProperty) + { + Object * parent = containedByProperty->getContainedBy (); + if (parent) + { + return parent->getVolumeContainerProperty(); + } + } + return NULL; + } + + const VolumeContainer* getVolumeContainerParent(const VolumeContainer& self) + { + const Object & owner = self.getOwner (); + const ContainedByProperty * const containedByProperty = owner.getContainedByProperty (); + if (containedByProperty) + { + const Object * const parent = containedByProperty->getContainedBy (); + if (parent) + { + return parent->getVolumeContainerProperty(); + } + } + return NULL; + } + + const unsigned int serverHolocronCrc = CrcLowerString::calculateCrc("object/player_quest/pgc_quest_holocron.iff"); +} + +using namespace VolumeContainerNamespace; + + +//----------------------------------------------------------------------- + +VolumeContainer::VolumeContainer(Object& owner, int totalVolume) : +Container(VolumeContainer::getClassPropertyId(), owner), +m_currentVolume(0), +m_totalVolume(totalVolume) +{ +} + +//----------------------------------------------------------------------- + +VolumeContainer::~VolumeContainer() +{ +} + +//----------------------------------------------------------------------- + +void VolumeContainer::childVolumeChanged(int volume, bool updateParent) +{ + if (m_totalVolume != VL_NoVolumeLimit) + m_currentVolume += volume; + + if (updateParent) + { + VolumeContainer *parent = getVolumeContainerParent(*this); + if (parent) + parent->childVolumeChanged(volume, true); + } +} + +//----------------------------------------------------------------------- + + +void VolumeContainer::insertNewItem(const Object & item, const VolumeContainmentProperty * itemProp) +{ + + const VolumeContainmentProperty * prop = itemProp ? itemProp : safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + WARNING_STRICT_FATAL(true, ("Item %s has no volume property", item.getNetworkId().getValueString().c_str())); + return; + } + if (m_totalVolume != VL_NoVolumeLimit) + m_currentVolume += prop->getVolume(); +} + +//----------------------------------------------------------------------- + +bool VolumeContainer::add (Object& item, ContainerErrorCode& error, bool allowOverloaded) +{ + // save off current volume + const int oldVolume = m_currentVolume; + + error = CEC_Success; + VolumeContainmentProperty * prop = safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + WARNING_STRICT_FATAL(true, ("Cannot add an item to a volume container without a containment property.")); + error = CEC_Unknown; + return false; + } + + if (!allowOverloaded && !checkVolume(*prop)) + { + error = CEC_Full; + return false; + } + + if (addToContents(item, error) == -1) + { + return false; + } + + insertNewItem(item, prop); + + // if volume has changed, update parent volume count + if (m_currentVolume != oldVolume) + { + VolumeContainer *parent = getVolumeContainerParent(*this); + if (parent) + parent->childVolumeChanged((m_currentVolume - oldVolume), true); + } + + return true; +} + +//----------------------------------------------------------------------- + +bool VolumeContainer::checkVolume (const VolumeContainmentProperty &item) const +{ + return checkVolume(item.getVolume()); +} + +//----------------------------------------------------------------------- + +bool VolumeContainer::checkVolume (int addedVolume) const +{ + if (m_totalVolume == VL_NoVolumeLimit) + return true; + + bool retval = false; + + retval = (m_currentVolume + addedVolume <= m_totalVolume); + +//-- check parent to make sure it isn't full + if (retval) + { + const VolumeContainer * const volumeContainer = getVolumeContainerParent(*this); + if (volumeContainer) + { + retval = volumeContainer->checkVolume(addedVolume); + } + } + return retval; +} +//----------------------------------------------------------------------- + +int VolumeContainer::debugDoNotUseSetCapacity(int newValue) +{ + int oldValue = m_totalVolume; + m_totalVolume = newValue; + return oldValue; +} + +//----------------------------------------------------------------------- + + +void VolumeContainer::debugPrint(std::string &buffer) const +{ + char tempBuffer[1024]; + + buffer += "====[BEGIN: volume container]====\n"; + + sprintf(tempBuffer, "container id [%s]: current volume [%d] total volume [%d].\n", getOwner().getNetworkId().getValueString().c_str(), + m_currentVolume, m_totalVolume); + buffer += tempBuffer; + + buffer += "embedding container contents now:\n"; + Container::debugPrint(buffer); + + buffer += "====[END: volume container]====\n"; +} + +//----------------------------------------------------------------------- + +PropertyId VolumeContainer::getClassPropertyId() +{ + return PROPERTY_HASH(VolumeContainer, 0xA5193F23); +} + +//----------------------------------------------------------------------- + + +bool VolumeContainer::mayAdd(const Object& item, ContainerErrorCode& error) const +{ + error = CEC_Success; + if (item.getNetworkId() == getOwner().getNetworkId()) + { + error = CEC_AddSelf; + return false; + } + + const VolumeContainmentProperty * prop = safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + error = CEC_Unknown; + return false; + } + + const VolumeContainer * vol = safe_cast(item.getProperty(VolumeContainer::getClassPropertyId())); + if (vol) + { + if (m_totalVolume != VL_NoVolumeLimit && vol->getTotalVolume() >= getTotalVolume()) + { + unsigned int ownerCrc = CrcLowerString::calculateCrc(getOwner().getObjectTemplateName()); + unsigned int itemCrc = CrcLowerString::calculateCrc(item.getObjectTemplateName()); + + if(ownerCrc == serverHolocronCrc && itemCrc == serverHolocronCrc) + { + // We're moving a holocron into another holocron, let it continue. + } + else + { + error = CEC_TooLarge; + return false; + } + + } + } + + if (!checkVolume(*prop)) + { + error = CEC_Full; + return false; + } + + return Container::mayAdd(item, error); +} + +//----------------------------------------------------------------------- + +int VolumeContainer::recalculateVolume() +{ + int volume = 0; + for (ContainerIterator iter = begin(); iter != end(); ++iter) + { + Object* const obj = (*iter).getObject(); + if (!obj) + { + WARNING_STRICT_FATAL(true, ("Container with non-existant object %s", (*iter).getValueString().c_str())); + } + else + { + VolumeContainmentProperty * const prop = safe_cast(obj->getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + WARNING_STRICT_FATAL(true, ("We have an item in a volume container with no property %s", (*iter).getValueString().c_str())); + } + else if (m_totalVolume != VL_NoVolumeLimit) + { + volume += prop->getVolume(); + } + + } + } + m_currentVolume = volume; + + //-- if our volume is recalculated, we must inform our parent if contained by a volume container + VolumeContainer * const volumeContainer = getVolumeContainerParent(*this); + if (volumeContainer) + IGNORE_RETURN (volumeContainer->recalculateVolume ()); + + WARNING_STRICT_FATAL(m_totalVolume > 0 && m_currentVolume > m_totalVolume, ("Recalculate Volume ended up being greater than our capacity")); + return m_currentVolume; +} + +//----------------------------------------------------------------------- + +bool VolumeContainer::internalRemove(const Object & item, const VolumeContainmentProperty * itemProp) +{ + const VolumeContainmentProperty * prop = itemProp ? itemProp : safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + WARNING_STRICT_FATAL(true, ("Item %s has no volume property", item.getNetworkId().getValueString().c_str())); + return false; + } + + if (m_totalVolume != VL_NoVolumeLimit) + m_currentVolume = m_currentVolume - prop->getVolume(); + + return true; +} + +//----------------------------------------------------------------------- + +bool VolumeContainer::remove (Object &item, ContainerErrorCode& error) +{ + // save off current volume + const int oldVolume = m_currentVolume; + + error = CEC_Success; + VolumeContainmentProperty * prop = safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (!prop) + { + WARNING_STRICT_FATAL(true, ("Cannot remove an item from a volume container without a containment property.")); + error = CEC_Unknown; + return false; + } + + bool retval = Container::remove(item, error); + if (!retval) + { + return false; + } + if (!internalRemove(item)) + { + WARNING_STRICT_FATAL(true, ("tried to remove item %s from volume container in internal routine but failed", item.getNetworkId().getValueString().c_str())); + error = CEC_Unknown; + return false; + } + + // if volume has changed, update parent volume count + if (m_currentVolume != oldVolume) + { + VolumeContainer *parent = getVolumeContainerParent(*this); + if (parent) + parent->childVolumeChanged((m_currentVolume - oldVolume), true); + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool VolumeContainer::remove(ContainerIterator &pos, ContainerErrorCode & error) +{ + error = CEC_Success; + Object *obj=(*pos).getObject(); + if (obj) + return remove(*obj, error); + else + { + error = CEC_Unknown; + return false; + } +} + +//----------------------------------------------------------------------- + +int VolumeContainer::depersistContents(const Object& item) +{ + // save off current volume + const int oldVolume = m_currentVolume; + + insertNewItem(item); + + // if volume has changed, update parent volume count + if (m_currentVolume != oldVolume) + { + // if we are contained in another volume container, we + // need up update the count in the parent container; + // however, if we are here because of a baseline, we don't + // need to update the parent container because when the + // parent adds us, it will update the count at that time; + // if we are here because of a delta, then we need to + // update the parent; if we are here because of a baseline, + // then we are not yet in the parent container, even though + // we have a pointer to the parent container + VolumeContainer *parent = getVolumeContainerParent(*this); + if (parent) + { + bool containedInParent = false; + + for (ContainerIterator i = parent->begin(); i != parent->end(); ++i) + { + if ((*i) == getOwner().getNetworkId()) + { + containedInParent = true; + break; + } + } + + if (containedInParent) + parent->childVolumeChanged((m_currentVolume - oldVolume), true); + } + } + + return Container::depersistContents(item); +} + + +//----------------------------------------------------------------------- + +bool VolumeContainer::internalItemRemoved(const Object& item) +{ + // save off current volume + const int oldVolume = m_currentVolume; + + if (internalRemove(item)) + { + // if volume has changed, update parent volume count + if (m_currentVolume != oldVolume) + { + const VolumeContainmentProperty * prop = safe_cast(item.getProperty(VolumeContainmentProperty::getClassPropertyId())); + if (prop) + { + VolumeContainer *parent = getVolumeContainerParent(*this); + if (parent) + parent->childVolumeChanged((m_currentVolume - oldVolume), true); + } + } + + return Container::internalItemRemoved(item); + } + return false; +} + +//---------------------------------------------------------------------- + +int VolumeContainer::getTotalVolumeLimitedByParents () const +{ + int totalVolume = m_totalVolume; + + //-- container is unlimited + if (totalVolume <= 0) + return totalVolume; + + int remainingVolume = m_totalVolume - m_currentVolume; + + const Object * parent = &getOwner (); + + while (parent) + { + const ContainedByProperty * const containedByProperty = parent->getContainedByProperty (); + + parent = containedByProperty->getContainedBy (); + if (parent) + { + const VolumeContainer * const volumeContainer = parent->getVolumeContainerProperty(); + if (!volumeContainer) + break; + + const int parentTotalVolume = volumeContainer->getTotalVolume (); + const int parentCurrentVolume = volumeContainer->getCurrentVolume (); + + //-- we've reached an unlimited container + if (parentTotalVolume <= 0) + break; + + const int remainingInParent = std::max (0, parentTotalVolume - parentCurrentVolume); + remainingVolume = std::min (remainingVolume, remainingInParent); + } + } + + return m_currentVolume + remainingVolume; +} + +//----------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.h b/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.h new file mode 100644 index 00000000..922154f7 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/VolumeContainer.h @@ -0,0 +1,98 @@ +// =============================================================== +// VolumeContainer.h +// copyright 2000 Verant Interactive +// All rights reserved +// =============================================================== + +#ifndef INCLUDED_VolumeContainer_H +#define INCLUDED_VolumeContainer_H + +//----------------------------------------------------------------------- + +#include "sharedObject/Container.h" +#include "Archive/AutoDeltaByteStream.h" + +//----------------------------------------------------------------------- + +class VolumeContainmentProperty; + +//----------------------------------------------------------------------- + +/** A volume container is a container that holds items, limited to a + * maximum volume. It represents things like chests, bags, etc. + */ +class VolumeContainer:public Container +{ + +public: + + static PropertyId getClassPropertyId(); + +public: + + VolumeContainer(Object& owner, int totalVolume); + ~VolumeContainer(); + + bool add (Object& item, ContainerErrorCode& error, bool allowOverloaded = false); + bool checkVolume(int addedVolume) const; + int getCurrentVolume () const; + int getTotalVolume () const; + int getTotalVolumeLimitedByParents () const; + virtual bool mayAdd (const Object& item, ContainerErrorCode& error) const; + int recalculateVolume(); + virtual bool remove (Object &item, ContainerErrorCode& error); + virtual bool remove (ContainerIterator &pos, ContainerErrorCode& error); + + virtual void debugPrint(std::string &buffer) const; + + // persistence interface: + // @todo would be nice to protect this somehow. + // but no good way now so DO NOT CALL THESE FUNCTIONS DIRECTLY + virtual int depersistContents(const Object& item); + virtual bool internalItemRemoved(const Object& item); + + int debugDoNotUseSetCapacity(int newValue); + + enum + { + VL_NoVolumeLimit = -1 + }; +private: + int m_currentVolume; + int m_totalVolume; + +public: + /** Called by the loader to add an item. + */ + void addItemFromLoader(int objectId); + +private: + bool checkVolume(const VolumeContainmentProperty &item) const; + + bool internalRemove(const Object & item, const VolumeContainmentProperty *itemProp = NULL); + void insertNewItem(const Object & item, const VolumeContainmentProperty *itemProp = NULL); + + void childVolumeChanged(int volume, bool updateParent); + + VolumeContainer(); + VolumeContainer(const VolumeContainer&); + VolumeContainer& operator=(const VolumeContainer&); +}; + +//----------------------------------------------------------------------- + +inline int VolumeContainer::getCurrentVolume() const +{ + return m_currentVolume; +} + +//----------------------------------------------------------------------- + +inline int VolumeContainer::getTotalVolume() const +{ + return m_totalVolume; +} + +//----------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.cpp b/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.cpp new file mode 100644 index 00000000..de3481a0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.cpp @@ -0,0 +1,62 @@ +// ====================================================================== +// +// VolumeContainmentProperty.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/VolumeContainmentProperty.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/VolumeContainer.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(VolumeContainmentProperty, true, 0, 0, 0); + +// ====================================================================== + +VolumeContainmentProperty::VolumeContainmentProperty(Object& owner, int volume) : +Property(VolumeContainmentProperty::getClassPropertyId(), owner), +m_volume(volume) +{ + +} + +//---------------------------------------------------------------------- + +void VolumeContainmentProperty::setVolume (int volume) +{ + m_volume = volume; +} + +// ----------------------------------------------------------- + +VolumeContainmentProperty::~VolumeContainmentProperty() +{ +} + +// ----------------------------------------------------------- + +PropertyId VolumeContainmentProperty::getClassPropertyId() +{ + return PROPERTY_HASH(VolumeContainment, 0x8701647C); +} + +// ----------------------------------------------------------- + +int VolumeContainmentProperty::getVolume() const +{ + int retval = m_volume; + const VolumeContainer* container = getOwner().getVolumeContainerProperty(); + if (container) + { + retval += container->getCurrentVolume(); + } + return retval; +} + +//----------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.h b/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.h new file mode 100644 index 00000000..c26fc14d --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/container/VolumeContainmentProperty.h @@ -0,0 +1,48 @@ +// ====================================================================== +// +// VolumeContainmentProperty.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_VolumeContainmentProperty_H +#define INCLUDED_VolumeContainmentProperty_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/Property.h" + +// ====================================================================== + +class VolumeContainmentProperty : public Property +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + static PropertyId getClassPropertyId(); + +public: + + VolumeContainmentProperty(Object& owner, int volume); + ~VolumeContainmentProperty(); + + int getVolume () const; + void setVolume (int volume); + +private: + int m_volume; + + VolumeContainmentProperty(); + VolumeContainmentProperty(const VolumeContainmentProperty&); + VolumeContainmentProperty& operator= (const VolumeContainmentProperty&); + +}; +// ----------------------------------------------------------- + + + + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/controller/Controller.cpp b/engine/shared/library/sharedObject/src/shared/controller/Controller.cpp new file mode 100644 index 00000000..66572a6a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/Controller.cpp @@ -0,0 +1,267 @@ +// ====================================================================== +// +// Controller.cpp +// copyright 1998 Bootprint Entertainment +// Copyright 2000-2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Controller.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/Object.h" +#include "sharedFoundation/Clock.h" + +// ====================================================================== + +Controller::Controller(Object *const owner) : + m_messageQueue(new MessageQueue(16)), + m_owner(owner) +{ +} + +// ---------------------------------------------------------------------- + +Controller::~Controller() +{ + HeldMessageMap::iterator iter; + for ( iter = m_heldMessages.begin(); iter != m_heldMessages.end(); ++iter ) + { + delete( iter->second.data ); + } + m_heldMessages.clear(); + + + delete m_messageQueue; + + m_owner = 0; +} + +// ---------------------------------------------------------------------- + +float Controller::alter(float time) +{ + NOT_NULL(m_messageQueue); + m_messageQueue->beginFrame(); + + processHeldMessages(); + + return realAlter(time); +} + +// ---------------------------------------------------------------------- + +void Controller::conclude() +{ +} + +// ---------------------------------------------------------------------- + +void Controller::setOwner(Object *const owner) +{ + m_owner = owner; +} + + +// +// Hold onto this message for a while before sending +// +void Controller::holdMessage( int holdMs, int message, float value, MessageQueue::Data *data, uint32 flags) +{ + if ( m_heldMessages.count(message) ) // only one per type + sendHeldMessage( message ); + m_heldMessages[ message ].sendTime = Clock::getCurrentTime() + (double(holdMs) / 1000.0); + m_heldMessages[ message ].value = value; + m_heldMessages[ message ].data = data; + m_heldMessages[ message ].flags = flags; + + if (m_owner && m_owner->isInitialized()) + m_owner->scheduleForAlter(); +} + +// +// Check out the current held message +// +MessageQueue::Data* Controller::peekHeldMessage( int message, float *value, uint32 *flags ) +{ + HeldMessageMap::iterator iter = m_heldMessages.find( message ); + if ( iter == m_heldMessages.end() ) + return NULL; + if ( value ) + *value = iter->second.value; + if ( flags ) + *flags = iter->second.flags; + return iter->second.data; +} + +// +// Cause the held message of this type to get sent now +// +void Controller::sendHeldMessage( int message ) +{ + HeldMessageMap::iterator iter = m_heldMessages.find( message ); + if ( iter == m_heldMessages.end() ) + return; + appendMessage( message, iter->second.value, iter->second.data, iter->second.flags ); + m_heldMessages.erase( iter ); +} + +// +// Cause the held message of this type to get sent if the hold time has expired +// +void Controller::processHeldMessages( void ) +{ + double now = Clock::getCurrentTime(); + HeldMessageMap::iterator iter; + for ( iter = m_heldMessages.begin(); iter != m_heldMessages.end(); ) + { + if ( iter->second.sendTime <= now ) + { + appendMessage( iter->first, iter->second.value, iter->second.data, iter->second.flags ); + m_heldMessages.erase( iter++ ); + } + else + { + ++iter; + } + } + if ( ! m_heldMessages.empty() ) + { + if (m_owner && m_owner->isInitialized()) + m_owner->scheduleForAlter(); + } +} + + + +// ---------------------------------------------------------------------- + +void Controller::appendMessage(const int message, const float value, const uint32 flags) +{ + NOT_NULL(m_messageQueue); + m_messageQueue->appendMessage(message, value, flags); + + if (message==0) + { + WARNING(true, ("trying to append message 0")); + } + + //-- We must guarantee that the owner object gets an alter to process this message. + // @todo resolve: if this object is handled via object lists (e.g. a UI object), this + // should not go on the alter scheduler. + if (m_owner && m_owner->isInitialized()) + m_owner->scheduleForAlter(); +} + +// ---------------------------------------------------------------------- + +void Controller::appendMessage(const int message, const float value, MessageQueue::Data *const data, const uint32 flags) +{ + NOT_NULL(m_messageQueue); + m_messageQueue->appendMessage(message, value, data, flags); + + //-- We must guarantee that the owner object gets an alter to process this message. + // @todo resolve: if this object is handled via object lists (e.g. a UI object), this + // should not go on the alter scheduler. + if (m_owner && m_owner->isInitialized()) + m_owner->scheduleForAlter(); +} + +// ---------------------------------------------------------------------- + +int Controller::getNumberOfMessages() const +{ + return m_messageQueue->getNumberOfMessages(); +} + +// ---------------------------------------------------------------------- + +void Controller::getMessage(int index, int *message, float *value, uint32 *flags) const +{ + m_messageQueue->getMessage(index, message, value, flags); +} + +// ---------------------------------------------------------------------- + +void Controller::getMessage(int index, int *message, float *value, MessageQueue::Data **data, uint32 *flags) const +{ + m_messageQueue->getMessage(index, message, value, data, flags); +} + +// ---------------------------------------------------------------------- + +void Controller::clearMessageAndData(int index) +{ + m_messageQueue->clearMessageData(index); + m_messageQueue->clearMessage(index); +} + +// ---------------------------------------------------------------------- + +void Controller::setMessageQueueNotification(MessageQueue::Notification *notification) +{ + m_messageQueue->setNotification(notification); +} + +//---------------------------------------------------------------------- + +MessageQueue * Controller::getMessageQueue() +{ + return m_messageQueue; +} + +//---------------------------------------------------------------------- + +TangibleController * Controller::asTangibleController() +{ + return NULL; +} + +//---------------------------------------------------------------------- + +TangibleController const * Controller::asTangibleController() const +{ + return NULL; +} + +//---------------------------------------------------------------------- + +CreatureController * Controller::asCreatureController() +{ + return NULL; +} + +//---------------------------------------------------------------------- + +CreatureController const * Controller::asCreatureController() const +{ + return NULL; +} + +//---------------------------------------------------------------------- + +ShipController * Controller::asShipController() +{ + return NULL; +} + +//---------------------------------------------------------------------- + +ShipController const * Controller::asShipController() const +{ + return NULL; +} + +// ====================================================================== +// PROTECTED Controller +// ====================================================================== + +float Controller::realAlter(float /*time*/) +{ + // Indicate that no alter is required for this class' functionality. + return AlterResult::cms_keepNoAlter; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/controller/Controller.h b/engine/shared/library/sharedObject/src/shared/controller/Controller.h new file mode 100644 index 00000000..02150ea9 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/Controller.h @@ -0,0 +1,114 @@ +// ====================================================================== +// +// Controller.h +// copyright 1998 Bootprint Entertainment +// Copyright 2000-2001 Sony Online Entertainment +// All Rights Reserved. +// +// Abstract controller entity for an object +// +// ====================================================================== + +#ifndef INCLUDED_Controller_H +#define INCLUDED_Controller_H + +// ====================================================================== + +#include "sharedFoundation/MessageQueue.h" +#include + +class CreatureController; +class Object; +class ShipController; +class TangibleController; + +// ====================================================================== + +class Controller +{ +public: + + explicit Controller(Object *owner); + virtual ~Controller(); + + float alter(float time); + virtual void conclude(); + + virtual TangibleController * asTangibleController(); + virtual TangibleController const * asTangibleController() const; + + virtual CreatureController * asCreatureController(); + virtual CreatureController const * asCreatureController() const; + + virtual ShipController * asShipController(); + virtual ShipController const * asShipController() const; + + virtual void setOwner(Object *newOwner); + Object *getOwner(); + const Object *getOwner() const; + + // hold message for a little while before sending + // only one message per type may be held + void holdMessage( int holdMs, int message, float value, MessageQueue::Data *data, uint32 flags=0); + MessageQueue::Data* peekHeldMessage( int message, float *value=0, uint32 *flags=0 ); + void sendHeldMessage( int message ); + void processHeldMessages( void ); + + void appendMessage(int message, float value, uint32 flags=0); + void appendMessage(int message, float value, MessageQueue::Data *data, uint32 flags=0); + + int getNumberOfMessages() const; + void getMessage(int index, int *message, float *value, uint32 *flags=0) const; + void getMessage(int index, int *message, float *value, MessageQueue::Data **data, uint32 *flags=0) const; + void clearMessageAndData(int i); + + void setMessageQueueNotification(MessageQueue::Notification *notification); + + MessageQueue * getMessageQueue(); + +protected: + + struct HeldMessageInfo + { + double sendTime; + float value; + MessageQueue::Data* data; + uint32 flags; + }; + + virtual float realAlter(float time); + +private: + + Controller(); + Controller(const Controller &); + Controller &operator =(const Controller &); + +protected: + typedef std::map< int, HeldMessageInfo > HeldMessageMap; + HeldMessageMap m_heldMessages; // message type -> held info + + MessageQueue *const m_messageQueue; + +private: + + Object *m_owner; +}; + +// ====================================================================== + +inline Object *Controller::getOwner() +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline const Object *Controller::getOwner() const +{ + return m_owner; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/controller/NetworkController.cpp b/engine/shared/library/sharedObject/src/shared/controller/NetworkController.cpp new file mode 100644 index 00000000..a3e34482 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/NetworkController.cpp @@ -0,0 +1,139 @@ +// ====================================================================== +// +// NetworkController.cpp +// copyright 2000 Verant Interactive +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/NetworkController.h" + +#include "sharedFoundation/NetworkIdArchive.h" +#include "sharedNetworkMessages/MessageQueueDataTransform.h" +#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" +#include "sharedNetworkMessages/ObjectChannelMessages.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedObject/Object.h" + +//----------------------------------------------------------------------- + +NetworkController::NetworkController(Object *const owner) : + Controller(owner) +{ +} + +//----------------------------------------------------------------------- + +NetworkController::~NetworkController() +{ +} + +//----------------------------------------------------------------------- + +void NetworkController::conclude() +{ + //-- if the object is valid + const Object *const object = getOwner (); + if (object) + { + //-- if the network id is valid + const NetworkId networkId = object->getNetworkId (); + if (networkId != NetworkId::cms_invalid) + { + int const messageCount = getNumberOfMessages (); + for (int i = 0; i < messageCount; ++i) + { + int message; + float value; + uint32 flags; + MessageQueue::Data* data; + getMessage (i, &message, &value, &data, &flags); + + if (message == 0) + { +// WARNING(true, ("Pulled message with id 0 from queue")); + } + //-- if the message is flagged for sending + else if (flags & GameControllerMessageFlags::SEND) + { + DEBUG_FATAL ((flags & GameControllerMessageFlags::DESTINATIONS) == 0, ("SEND controller message %d with no destination!", message)); + + const ObjControllerMessage c (networkId, static_cast(message), value, flags, data); + sendControllerMessage (c); + } + + //-- delete the message queue data if it exists + if (data) + { + if ((flags & GameControllerMessageFlags::SEND) != 0 || + (flags & GameControllerMessageFlags::SOURCE_REMOTE_SERVER) != 0 || + (flags & GameControllerMessageFlags::SOURCE_REMOTE_CLIENT) != 0) + { + clearMessageAndData (i); + + delete data; + data = 0; + } + } + } + } + } + + //-- chain up to the base class + Controller::conclude (); +} + +//----------------------------------------------------------------------- + +bool NetworkController::getAuthoritative() const +{ + return getOwner()->isAuthoritative(); +} + +//----------------------------------------------------------------------- +/** + * Processes a message. + * + * @param message message id + * @param data message data + * @param value message value + * @param time time since last update + * @param flags delivery flags + */ +void NetworkController::handleMessage (const int message, const float /*value*/, const MessageQueue::Data* const data, const uint32 /*flags*/) +{ + switch (message) + { + case CM_netUpdateTransformWithParent: + { + const MessageQueueDataTransformWithParent *const messageData = dynamic_cast(data); + if (messageData) + handleNetUpdateTransformWithParent(*messageData); + } + break; + + case CM_netUpdateTransform: + { + const MessageQueueDataTransform *const messageData = dynamic_cast(data); + if (messageData) + handleNetUpdateTransform(*messageData); + } + break; + default: + break; + } +} + +//----------------------------------------------------------------------- + +/** + * Sets this controller's object to be authoritative. + * + * @param authoritative authoritative flag + */ +void NetworkController::setAuthoritative(bool authoritative) +{ + getOwner()->setAuthoritative(authoritative); +} + +//----------------------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/controller/NetworkController.h b/engine/shared/library/sharedObject/src/shared/controller/NetworkController.h new file mode 100644 index 00000000..d941a2e5 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/NetworkController.h @@ -0,0 +1,58 @@ +// ====================================================================== +// +// NetworkController.h +// copyright 2000 Verant Interactive +// +// ====================================================================== + +#ifndef INCLUDED_NetworkController_H +#define INCLUDED_NetworkController_H + +// ====================================================================== + +#include "sharedObject/Controller.h" + +class Baselines; +class GameNetworkMessage; +class MessageQueueDataTransform; +class MessageQueueDataTransformWithParent; +class MessageQueueSetMemberData; +class ObjControllerMessage; + +// ====================================================================== + +class NetworkController : public Controller +{ +public: + + explicit NetworkController(Object* newOwner); + virtual ~NetworkController(); + + /** + NetworkController::conclude() gathers all messages in it's + message queue and sends those with the ControllerMessageFlag::SEND + option set. + */ + virtual void conclude (); + + virtual void sendControllerMessage(const ObjControllerMessage& msg) = 0; + + bool getAuthoritative () const; + virtual void setAuthoritative (bool newAuthoritative); + +protected: + + virtual void handleMessage (int message, float value, const MessageQueue::Data* data, uint32 flags); + virtual void handleNetUpdateTransform (const MessageQueueDataTransform& message) = 0; + virtual void handleNetUpdateTransformWithParent (const MessageQueueDataTransformWithParent& message) = 0; + +private: + + NetworkController(); + NetworkController(const NetworkController & other); + NetworkController& operator=(const NetworkController & rhs); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.def b/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.def new file mode 100644 index 00000000..155f0777 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.def @@ -0,0 +1,83 @@ +//======================================================================== +// +// ObjectSetMessage.def - sub-message ids for controller message CM_setMemberData +// +// copyright 2001 Sony Online Entertainment +// +// data files should be including ObjectSetMessage.def +// code files should be including ObjectSetMessage.h +// +//======================================================================== + +#ifndef _INCLUDED_ObjectSetMessage_DEF +#define _INCLUDED_ObjectSetMessage_DEF + +#ifndef _INCLUDED_ObjectSetMessage_H +#error include ObjectSetMessage.h instead of ObjectSetMessage.def +#endif + +enum ObjectSetMessage +{ + OSM_nothing, + + // ids for StarwarsObject and below + OSM_game_FIRST, + OSM_game_objectName, + OSM_game_sceneId, + OSM_game_LAST, + + // ids for TangibleObject + OSM_tangible_FIRST, // all Tangible properties are > OSM_tangible_FIRST + OSM_tangible_armorEffectiveness, + OSM_tangible_decayTime, + OSM_tangible_hitPoints, + OSM_tangible_isFrozen, + OSM_tangible_isSquelched, + OSM_tangible_maxHitPoints, + OSM_tangible_ownerId, + OSM_tangible_popupHelpId, + OSM_tangible_qualityRating, + OSM_tangible_visible, + OSM_tangible_weight, + OSM_tangible_LAST, // all Tangible properties are < OSM_tangible_LAST + + // ids for CreatureObject + OSM_creature_FIRST, + OSM_creature_attributes, // takes an index and value + OSM_creature_maxAttributes, // takes an index and value + OSM_creature_gender, + OSM_creature_LAST, + + // ids for VehicleObject + OSM_vehicle_FIRST, + OSM_vehicle_bogus, + OSM_vehicle_LAST, + + // ids for BuildingObject + OSM_building_FIRST, + OSM_building_LAST, + + // ids for VenueObject + OSM_venue_FIRST, + OSM_venue_LAST, + + // ids for InstallationObject + OSM_installation_FIRST, + OSM_installation_LAST, + + // ids for ProducerObject + OSM_producer_FIRST, + OSM_producer_LAST, + + // ids for CountingObject + OSM_counting_FIRST, + OSM_counting_LAST, + + // ids for WeaponObject + OSM_weapon_FIRST, + OSM_weapon_LAST, + + OSM_last +}; + +#endif // _INCLUDED_ObjectSetMessage_DEF diff --git a/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.h b/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.h new file mode 100644 index 00000000..97886bd6 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/ObjectSetMessage.h @@ -0,0 +1,42 @@ +//======================================================================== +// +// ObjectSetMessage.def - sub-message ids for controller message CM_setMemberData +// +// copyright 2001 Sony Online Entertainment +// +// data files should be including ObjectSetMessage.def +// code files should be including ObjectSetMessage.h +// +//======================================================================== + +#ifndef _INCLUDED_ObjectSetMessage_H +#define _INCLUDED_ObjectSetMessage_H + +#include "sharedObject/ObjectSetMessage.def" + +// data types for ObjectSetMessage +enum OsmDataType +{ + ODT_bool, // maps to bool + ODT_char, // maps to char + ODT_int16, // maps to int16 + ODT_int32, // maps to int32 + ODT_uint16, // maps to uint16 + ODT_uint32, // maps to uint32 + ODT_real, // maps to real + ODT_stdstring, // maps to an stl string + ODT_unicodestring, // maps to our unicode wide character strings + ODT_attrib // maps to struct OdtAttribute +}; + + + +// types for CreatureObject +struct OdtAttribute +{ + signed char type; // attribute type (CreatureObject::AttributeEnumerator) + int16 value; // attribute value +}; + + +#endif // _INCLUDED_ObjectSetMessage_H diff --git a/engine/shared/library/sharedObject/src/shared/controller/printCmValues.pl b/engine/shared/library/sharedObject/src/shared/controller/printCmValues.pl new file mode 100644 index 00000000..4d4aa1e5 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/controller/printCmValues.pl @@ -0,0 +1,10 @@ +$value = 0; + +while (<>) +{ + if (/(CM_[^,]+)/) + { + print "$1: $value\n"; + ++$value; + } +} \ No newline at end of file diff --git a/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.cpp b/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.cpp new file mode 100644 index 00000000..0cd6c668 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.cpp @@ -0,0 +1,168 @@ +// ===================================================================== +// +// ConfigSharedObject.cpp +// asommers +// +// copyright 2002, sony online entertainment +// +// ===================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ConfigSharedObject.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/ConfigFile.h" + +// ===================================================================== + +#define KEY_BOOL(s, a,b) (ms_ ## a = ConfigFile::getKeyBool(s, #a, b)) +#define KEY_INT(s, a,b) (ms_ ## a = ConfigFile::getKeyInt(s, #a, b)) +#define KEY_FLOAT(s, a,b) (ms_ ## a = ConfigFile::getKeyFloat(s, #a, b)) +//#define KEY_STRING(a,b) (ms_ ## a = ConfigFile::getKeyString("SharedObject", #a, b)) + +// ===================================================================== +// ConfigSharedObjectNamespace +// ===================================================================== + +namespace ConfigSharedObjectNamespace +{ + float ms_portalScale; + bool ms_allowDisabledPortals; + float ms_appearanceTemplateListKeepTime; + float ms_appearanceTemplateListKeepEpsilon; + bool ms_validateCellContentsAttached; + bool ms_validateWorld; + + int ms_alterSchedulerNoAlterScheduleDelay; + + bool ms_logCustomizationDataIssues; + + bool ms_debugAlterChecking; + + bool ms_containerLoopChecking; + int ms_containerMaxDepth; + + bool ms_allowDisallowObjectDelete; +} + +using namespace ConfigSharedObjectNamespace; + +// ===================================================================== +// STATIC PUBLIC ConfigSharedObjectNamespace +// ===================================================================== + +void ConfigSharedObject::install() +{ + KEY_FLOAT ("SharedObject", portalScale, 1.1f); + KEY_BOOL("SharedObject", allowDisabledPortals, false); + KEY_FLOAT ("SharedObject", appearanceTemplateListKeepTime, 15.f); + KEY_FLOAT ("SharedObject", appearanceTemplateListKeepEpsilon, 5.f); + KEY_BOOL ("SharedObject", validateCellContentsAttached, true); + KEY_BOOL ("SharedObject", validateWorld, false); + KEY_BOOL ("SharedObject", logCustomizationDataIssues, false); + + KEY_INT ("SharedObject/AlterScheduler", alterSchedulerNoAlterScheduleDelay, 0); + + KEY_BOOL ("SharedObject", debugAlterChecking, false); + + KEY_BOOL ("SharedObject", containerLoopChecking, true); + KEY_INT ("SharedObject", containerMaxDepth, 9); + + KEY_BOOL ("SharedObject", allowDisallowObjectDelete, true); +} + +// ===================================================================== +// STATIC PRIVATE ConfigSharedObjectNamespace +// ===================================================================== + +float ConfigSharedObject::getPortalScale () +{ + return ms_portalScale; +} + +// --------------------------------------------------------------------- + +bool ConfigSharedObject::getAllowDisabledPortals() +{ + return ms_allowDisabledPortals; +} + +// --------------------------------------------------------------------- + +float ConfigSharedObject::getAppearanceTemplateListKeepTime () +{ + return ms_appearanceTemplateListKeepTime; +} + +// --------------------------------------------------------------------- + +float ConfigSharedObject::getAppearanceTemplateListKeepEpsilon () +{ + return ms_appearanceTemplateListKeepEpsilon; +} + +// --------------------------------------------------------------------- + +bool ConfigSharedObject::getValidateCellContentsAttached () +{ + return ms_validateCellContentsAttached; +} + +// --------------------------------------------------------------------- + +bool ConfigSharedObject::getValidateWorld () +{ + return ms_validateWorld; +} + +// ---------------------------------------------------------------------- +/** + * If set to non-zero, the alter scheduler will schedule objects requesting + * no alter at this return value's number of seconds into the future. + * + * @return the number of seconds in the future in which no-alter-desired objects + * will be altered into the future. + */ + +int ConfigSharedObject::getAlterSchedulerNoAlterScheduleDelay () +{ + return ms_alterSchedulerNoAlterScheduleDelay; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedObject::getLogCustomizationDataIssues () +{ + return ms_logCustomizationDataIssues; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedObject::getDebugAlterChecking() +{ + return ms_debugAlterChecking; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedObject::getContainerLoopChecking() +{ + return ms_containerLoopChecking; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedObject::getContainerMaxDepth() +{ + return ms_containerMaxDepth; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedObject::getAllowDisallowObjectDelete() +{ + return ms_allowDisallowObjectDelete; +} + +// ===================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.h b/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.h new file mode 100644 index 00000000..f5ddf617 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/core/ConfigSharedObject.h @@ -0,0 +1,47 @@ +// ===================================================================== +// +// ConfigSharedObject.h +// asommers +// +// copyright 2002, sony online entertainment +// +// ===================================================================== + +#ifndef INCLUDED_ConfigSharedObject_H +#define INCLUDED_ConfigSharedObject_H + +// ===================================================================== + +class ConfigSharedObject +{ +public: + + static void install (); + + static float getPortalScale (); + static bool getAllowDisabledPortals(); + static float getAppearanceTemplateListKeepTime (); + static float getAppearanceTemplateListKeepEpsilon (); + static bool getValidateCellContentsAttached (); + static bool getValidateWorld (); + + static int getAlterSchedulerNoAlterScheduleDelay (); + + static bool getLogCustomizationDataIssues (); + + static bool getDebugAlterChecking(); + + static bool getContainerLoopChecking(); + static int getContainerMaxDepth(); + + static bool getAllowDisallowObjectDelete(); +private: + + ConfigSharedObject (); + ConfigSharedObject (const ConfigSharedObject&); + ConfigSharedObject& operator= (const ConfigSharedObject&); +}; + +// ===================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/core/FirstSharedObject.h b/engine/shared/library/sharedObject/src/shared/core/FirstSharedObject.h new file mode 100644 index 00000000..2ef4c735 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/core/FirstSharedObject.h @@ -0,0 +1,18 @@ +// ====================================================================== +// +// FirstObject.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstObject_H +#define INCLUDED_FirstObject_H + +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.cpp b/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.cpp new file mode 100644 index 00000000..69799beb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.cpp @@ -0,0 +1,195 @@ +// ====================================================================== +// +// SetupSharedObject.cpp +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SetupSharedObject.h" + +#include "sharedCollision/ExtentList.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/ArrangementDescriptorList.h" +#include "sharedObject/BasicRangedIntCustomizationVariable.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/CustomizationIdManager.h" +#include "sharedObject/MemoryBlockManagedObject.h" +#include "sharedObject/MovementTable.h" +#include "sharedObject/NoRenderAppearanceTemplate.h" +#include "sharedObject/Object.h" +#include "sharedObject/ObjectTemplate.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/PaletteColorCustomizationVariable.h" +#include "sharedObject/PortalPropertyTemplate.h" +#include "sharedObject/ScheduleData.h" +#include "sharedObject/SlotDescriptorList.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/TrackingDynamics.h" +#include "sharedObject/VolumeContainmentProperty.h" +#include "sharedDebug/InstallTimer.h" + +#include + +// ====================================================================== +// class SetupSharedObject::Data +// ====================================================================== + +SetupSharedObject::Data::Data() +: version(0), + useContainers(false), + slotDefinitionFilename(new std::string("")), + loadAssociatedHardpointNames(false), + useMovementTable(false), + movementStateTableFilename(new std::string("")), + useTimedAppearanceTemplates(false), + ensureDefaultAppearanceExists(true), + customizationIdManagerFilename(0), + objectsAlterChildrenAndContents(true), + loadObjectTemplateCrcStringTable(true), + pobEjectionTransformFilename(NULL) +{ +} + +// ---------------------------------------------------------------------- + +SetupSharedObject::Data::~Data() +{ + delete customizationIdManagerFilename; + delete movementStateTableFilename; + delete slotDefinitionFilename; +} + +// ====================================================================== +// class SetupSharedObject +// ====================================================================== +/** + * Install sharedObject. + * + * The settings in the Data structure will determine which subsystems + * get initialized. + */ + +void SetupSharedObject::install(const Data &data) +{ + InstallTimer const installTimer("SetupSharedObject::install"); + + DEBUG_FATAL(data.version != DATA_VERSION, ("SetupSharedObject::install wrong version %d/%d", data.version, DATA_VERSION)); + + ConfigSharedObject::install(); + + ScheduleData::install(); + + Appearance::install(); + AppearanceTemplateList::install(data.useTimedAppearanceTemplates, data.ensureDefaultAppearanceExists); + NoRenderAppearanceTemplate::install(); + + // this is needed by plug-ins that aren't using the rest of the 3d system + ExtentList::install(); + ObjectTemplateList::install(data.loadObjectTemplateCrcStringTable); + ObjectTemplate::install(); + Object::install(data.objectsAlterChildrenAndContents); + MemoryBlockManagedObject::install(); + CellProperty::install(); + AppearanceTemplate::install(); + ContainedByProperty::install(); + SlottedContainmentProperty::install(); + VolumeContainmentProperty::install(); + + CustomizationData::install(); + BasicRangedIntCustomizationVariable::install(); + PaletteColorCustomizationVariable::install(); + PortalPropertyTemplate::install(data.pobEjectionTransformFilename); + + // Dynamics. + TrackingDynamics::install(); + + // install container-related systems + if (data.useContainers) + { + DEBUG_FATAL(data.slotDefinitionFilename->empty(), ("must specify a slotDefinitionFilename if you're using containers\n")); + + SlotIdManager::install(*data.slotDefinitionFilename, data.loadAssociatedHardpointNames); + SlotDescriptorList::install(); + ArrangementDescriptorList::install(); + } + + // install movement table + if (data.useMovementTable) + { + DEBUG_FATAL(data.movementStateTableFilename->empty(), ("must specify a movementStateTableFilename if using the movement table\n")); + MovementTable::install(*data.movementStateTableFilename); + } + + AlterScheduler::install(); + + // Optionally install customization id manager + if (data.customizationIdManagerFilename) + CustomizationIdManager::install(data.customizationIdManagerFilename->c_str()); +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::setupDefaultGameData(Data &data) +{ + data.version = DATA_VERSION; +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::setupDefaultConsoleData(Data &data) +{ + data.version = DATA_VERSION; + data.loadObjectTemplateCrcStringTable = false; +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::setupDefaultMFCData(Data &data) +{ + data.version = DATA_VERSION; +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::addSlotIdManagerData(Data &data, bool loadAssociatedHardpointNames) +{ + data.useContainers = true; + *data.slotDefinitionFilename = "abstract/slot/slot_definition/slot_definitions.iff"; + data.loadAssociatedHardpointNames = loadAssociatedHardpointNames; +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::addMovementTableData(Data &data) +{ + data.useMovementTable = true; + *data.movementStateTableFilename = "datatables/movement/movementstates.iff"; +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::addCustomizationSupportData(Data &data) +{ + IS_NULL(data.customizationIdManagerFilename); + data.customizationIdManagerFilename = new std::string("customization/customization_id_manager.iff"); +} + +// ---------------------------------------------------------------------- + +void SetupSharedObject::addPobEjectionTransformData(Data &data) +{ + IS_NULL(data.pobEjectionTransformFilename); + data.pobEjectionTransformFilename = "datatables/pob/pob_ejection_point.iff"; +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.h b/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.h new file mode 100644 index 00000000..dd38e215 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/core/SetupSharedObject.h @@ -0,0 +1,100 @@ +// ====================================================================== +// +// SetupSharedObject.h +// copyright 1998 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SetupSharedObject_H +#define INCLUDED_SetupSharedObject_H + +// ====================================================================== + +class SetupSharedObject +{ +private: + + // **** INCREMENT THIS VERSION NUMBER WHENEVER THIS STRUCT CHANAGES **** + + // This enum is private so that a game can't use it directly. If the + // struct changes, the game programmers should be forced to look at the + // changes and update their data and version number manually. + + enum + { + DATA_VERSION = 13 + }; + +public: + + struct Data + { + public: + + Data(); + ~Data(); + + public: + + int version; + + // Specifies if Object container support should be installed. + bool useContainers; + + // Specifies the valid slot definition file. Must be specified + // if container support is installed. + std::string *slotDefinitionFilename; + + // If loading a slot definition file, this value controls if the + // hardpoint names associated with a slot are loaded. This should + // be set true for clients and false for servers. + bool loadAssociatedHardpointNames; + + // specifies if the movement state tables should be installed + bool useMovementTable; + std::string *movementStateTableFilename; + + bool useTimedAppearanceTemplates; + + bool ensureDefaultAppearanceExists; + + // Specifies the name of the customization id manager data file. + // Must be specified to use appearance customization system. + // See addCustomizationSupportData(). + std::string *customizationIdManagerFilename; + + // specifies whether objects should alter their child and contained objects, rather than expecting them to be scheduled separately + bool objectsAlterChildrenAndContents; + + // Specifies whether or not ObjectTemplateList should load the object template crc table + bool loadObjectTemplateCrcStringTable; + + // Specifies the name of the POB ejection point transform override filename to use; use NULL (default) if no ejection point support. + char const *pobEjectionTransformFilename; + + private: + + // disabled + Data(const Data&); + Data &operator =(const Data&); + + }; + +public: + + static void setupDefaultGameData(Data &data); + static void setupDefaultConsoleData(Data &data); + static void setupDefaultMFCData(Data &data); + + static void addSlotIdManagerData(Data &data, bool loadAssociatedHardpointNames); + static void addMovementTableData(Data &data); + static void addCustomizationSupportData(Data &data); + static void addPobEjectionTransformData(Data &data); + + static void install(const Data &data); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.cpp b/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.cpp new file mode 100644 index 00000000..48d2376a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.cpp @@ -0,0 +1,97 @@ +// ====================================================================== +// +// BasicRangedIntCustomizationVariable.cpp +// Copyright 2002, 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/BasicRangedIntCustomizationVariable.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/ObjectTemplateCustomizationDataWriter.h" + +#include +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(BasicRangedIntCustomizationVariable, true, 0, 0, 0); + +// ====================================================================== + +BasicRangedIntCustomizationVariable::BasicRangedIntCustomizationVariable(int minRangeInclusive, int value, int maxRangeExclusive) : + RangedIntCustomizationVariable(), + m_value(value), + m_minRangeInclusive(minRangeInclusive), + m_maxRangeExclusive(maxRangeExclusive) +{ +} + +// ---------------------------------------------------------------------- + +int BasicRangedIntCustomizationVariable::getValue() const +{ + return m_value; +} + +// ---------------------------------------------------------------------- + +bool BasicRangedIntCustomizationVariable::setValue(int value) +{ + if ((value >= m_minRangeInclusive) && (value < m_maxRangeExclusive)) + { + // change the value + m_value = value; + + // notify owner CustomizationData about change. + signalVariableModified(); + } + else + { + DEBUG_WARNING(true, ("attempted to set BasicRangedIntCustomizationVariable to %d, outside valid range [%d,%d).", value, m_minRangeInclusive, m_maxRangeExclusive)); + return false; + } + + return RangedIntCustomizationVariable::setValue(value); +} + +// ---------------------------------------------------------------------- + +void BasicRangedIntCustomizationVariable::getRange(int &minRangeInclusive, int &maxRangeExclusive) const +{ + minRangeInclusive = m_minRangeInclusive; + maxRangeExclusive = m_maxRangeExclusive; +} + +// ---------------------------------------------------------------------- + +void BasicRangedIntCustomizationVariable::writeObjectTemplateExportString(const std::string &variablePathName, ObjectTemplateCustomizationDataWriter &writer) const +{ +#if !(USE_OBJ_TEMPLATE_CUSTOM_VAR_WRITER) + UNREF(variablePathName); + UNREF(writer); +#else + //-- this assumes that the current value is the default value --- if the user changed values at all, they + // will not be the artist's built in default. + writer.addRangedIntCustomizationVariable(variablePathName, m_minRangeInclusive, m_value, m_maxRangeExclusive); +#endif +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +std::string BasicRangedIntCustomizationVariable::debugToString() const +{ + char buffer[128]; + + sprintf(buffer, "[%d,%d,%d)", m_minRangeInclusive, m_value, m_maxRangeExclusive); + return std::string(buffer); +} + +#endif + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.h b/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.h new file mode 100644 index 00000000..df66c3e0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/BasicRangedIntCustomizationVariable.h @@ -0,0 +1,57 @@ +// ====================================================================== +// +// BasicRangedIntCustomizationVariable.h +// Copyright 2002, 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_BasicRangedIntCustomizationVariable_H +#define INCLUDED_BasicRangedIntCustomizationVariable_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/RangedIntCustomizationVariable.h" + +class MemoryBlockManager; + +// ====================================================================== + +class BasicRangedIntCustomizationVariable: public RangedIntCustomizationVariable +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + BasicRangedIntCustomizationVariable(int minRangeInclusive, int value, int maxRangeExclusive); + + virtual int getValue() const; + virtual bool setValue(int value); + + virtual void getRange(int &minRangeInclusive, int &maxRangeExclusive) const; + + virtual void writeObjectTemplateExportString(const std::string &variablePathName, ObjectTemplateCustomizationDataWriter &writer) const; + +#ifdef _DEBUG + virtual std::string debugToString() const; +#endif + +private: + + // disabled + BasicRangedIntCustomizationVariable(); + BasicRangedIntCustomizationVariable(const BasicRangedIntCustomizationVariable&); + BasicRangedIntCustomizationVariable &operator =(const BasicRangedIntCustomizationVariable&); + +private: + + int m_value; + int m_minRangeInclusive; + int m_maxRangeExclusive; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.cpp b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.cpp new file mode 100644 index 00000000..d249819b --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.cpp @@ -0,0 +1,1326 @@ +// ====================================================================== +// +// CustomizationData.cpp +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationData.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedLog/Log.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/CustomizationData_Directory.h" +#include "sharedObject/CustomizationData_LocalDirectory.h" +#include "sharedObject/CustomizationData_RemoteDirectory.h" +#include "sharedObject/CustomizationIdManager.h" +#include "sharedObject/CustomizationVariable.h" +#include "sharedObject/Object.h" +#include "UnicodeUtils.h" + +#include +#include +#include +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITHOUT_INSTALL(CustomizationData, true, 0, 0, 0); + +// ====================================================================== + +const char CustomizationData::cms_directorySeparator = '/'; +const char CustomizationData::cms_stringFieldSeparator = '#'; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +bool CustomizationData::ms_installed; + +// ====================================================================== + +struct CustomizationData::ModificationCallbackData +{ +public: + + ModificationCallbackData(ModificationCallback callback, const void *context); + + bool operator ==(const ModificationCallbackData &rhs) const; + +public: + + ModificationCallback m_callback; + const void *m_context; + +private: + + // disabled + ModificationCallbackData(); +}; + +// ====================================================================== + +namespace CustomizationDataNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::vector > CustomizationVariableConstVector; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void collectPersistedVariablesCallback(std::string const &fullVariablePathName, CustomizationVariable const *customizationVariable, void *context); + void alterVariableCallback(std::string const &fullVariablePathName, CustomizationVariable *customizationVariable, void *context); +} + +using namespace CustomizationDataNamespace; + +// ====================================================================== +// namespace CustomizationDataNamespace +// ====================================================================== + +void CustomizationDataNamespace::collectPersistedVariablesCallback(std::string const &fullVariablePathName, CustomizationVariable const *customizationVariable, void *context) +{ + NOT_NULL(customizationVariable); + NOT_NULL(context); + + //-- Collect all customization variables that are persistable. + if (customizationVariable->doesVariablePersist()) + { + CustomizationVariableConstVector *const variablesToWrite = reinterpret_cast(context); + variablesToWrite->push_back(CustomizationVariableConstVector::value_type(fullVariablePathName, customizationVariable)); + } +} + +// ---------------------------------------------------------------------- + +void CustomizationDataNamespace::alterVariableCallback(std::string const &fullVariablePathName, CustomizationVariable *customizationVariable, void *context) +{ + UNREF(fullVariablePathName); + + NOT_NULL(customizationVariable); + NOT_NULL(context); + + CustomizationData *const customizationData = static_cast(context); + customizationVariable->alter(*customizationData); +} + +// ====================================================================== +// struct CustomizationData::ModificationCallbackData +// ====================================================================== + +CustomizationData::ModificationCallbackData::ModificationCallbackData(ModificationCallback callback, const void *context) +: m_callback(callback), + m_context(context) +{ +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::ModificationCallbackData::operator ==(const ModificationCallbackData &rhs) const +{ + return (rhs.m_callback == m_callback) && (rhs.m_context == m_context); +} + +// ====================================================================== +// class CustomizationData +// ====================================================================== + +void CustomizationData::install() +{ + DEBUG_FATAL(ms_installed, ("CustomizationData already installed.")); + + installMemoryBlockManager(); + + LocalDirectory::install(); + RemoteDirectory::install(); + + ms_installed = true; + ExitChain::add(remove, "CustomizationData"); +} + +// ---------------------------------------------------------------------- + +/** + * Parse an integer value from a string, starting from the specified + * position and returning the new read position. + * + * The string version of the integer is assumed to be in hexadecimal + * format, not decimal. It must end in the field separator character, + * (the '#' character as of this writing). + * + * @param data the string containing the integer to read. + * @param startPosition the 0-based index of the first character of + * the integer in the string. + * @param endPosition returns the new position to read data, one + * position past the separator character ending + * the int. A value of -1 indicates a malformed + * hex integer. + * + * @return the integer value of the string contents. + */ + +int CustomizationData::parseSeparatedHexInt(const std::string &data, int startPosition, int &endPosition) +{ + //-- find end of int portion of string + endPosition = static_cast(data.find(cms_stringFieldSeparator, static_cast(startPosition))); + if (endPosition == static_cast(std::string::npos)) + return static_cast(std::string::npos); + + //-- read value. + std::string intString(data, static_cast(startPosition), static_cast(endPosition)); + + int value = static_cast(std::string::npos); + const int scanResult = sscanf(intString.c_str(), "%x", &value); + + if (scanResult != 1) + { + // failed to scan hex int + endPosition = static_cast(std::string::npos); + value = static_cast(std::string::npos); + } + else + { + // scanned hex int. move pass the separator character. + ++endPosition; + } + + return value; +} + +// ---------------------------------------------------------------------- + +/** + * Parse an embedded string value from a string, starting from the specified + * position and returning the new read position. + * + * @param data the string containing the embedded string to read. + * @param startPosition the 0-based index of the first character of + * the embedded string. + * @param endPosition returns the new position to read data, one + * position past the separator character ending + * the embedded string. A value of -1 indicates a failure + * to read the embedded string. + * + * @return the embedded (i.e. field delimited) string. + */ + +std::string CustomizationData::parseSeparatedString(const std::string &data, int startPosition, int &endPosition) +{ + //-- find end of int portion of string + endPosition = static_cast(data.find(cms_stringFieldSeparator, static_cast(startPosition))); + if (endPosition == static_cast(std::string::npos)) + return std::string(""); + + //-- return the value, incrementing the end position past the separator character. + const std::string::size_type embeddedStringLength = static_cast(endPosition - startPosition); + ++endPosition; + + return std::string(data, static_cast(startPosition), embeddedStringLength); +} + +// ---------------------------------------------------------------------- +/** + * Build a return string that contains the byte values in decimal of the + * given source string. + * + * The return value is similar to using the Oracle SELECT DUMP format: + * + * length=<#bytes>: byte1, byte2, byte3, ... + */ + +std::string CustomizationData::makeSelectDumpFormat(char const *source) +{ + NOT_NULL(source); + + //-- Get length of source string. + size_t const sourceLength = strlen(source); + + //-- Reserve reasonable amount of space for destination string. + std::string returnString; + returnString.reserve(5 * sourceLength); + + //-- Build output header. + char workBuffer[128]; + IGNORE_RETURN(snprintf(workBuffer, sizeof(workBuffer) - 1, "length=%d: ", static_cast(sourceLength))); + workBuffer[sizeof(workBuffer) - 1] = '\0'; + + returnString += workBuffer; + + //-- Append the ASCII-ized ordinal for each character in the string. + for (size_t i = 0; i < sourceLength; ++i) + { + IGNORE_RETURN(snprintf(workBuffer, sizeof(workBuffer) - 1, "%d%s", static_cast(source[i]), (i < sourceLength - 1) ? ", " : "")); + workBuffer[sizeof(workBuffer) - 1] = '\0'; + returnString += workBuffer; + } + + return returnString; +} + +// ====================================================================== + +CustomizationData::CustomizationData(Object &owner) : + m_referenceCount(0), + m_owner(owner), + m_rootDirectory(0), + m_dependentCustomizationDataMap(0), + m_modificationCallbacks(new ModificationCallbackDataVector()) +{ + m_rootDirectory = new LocalDirectory(*this); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::addVariableTakeOwnership(const std::string &fullVariablePathName, CustomizationVariable *variable) +{ + //-- check for null variable + if (!variable) + { + WARNING(true, ("addVariableTakeOwnership() called with null variable.\n")); + return; + } + + //-- find the directory to which we'll add the given variable + const bool traverseRemoteDirectories = false; + const bool createLocalMissingDirectories = true; + int variableNameStartIndex = 0; + + Directory *const targetDirectory = findDirectoryFromPathName(fullVariablePathName, traverseRemoteDirectories, createLocalMissingDirectories, variableNameStartIndex); + if (!targetDirectory) + { + WARNING(true, ("addVariableTakeOwnership(): failed to resolve full variable pathname [%s] to local customization directory.\n", fullVariablePathName.c_str())); + delete variable; + return; + } + + //-- add the variable + const bool addSuccess = targetDirectory->addVariableTakeOwnership(fullVariablePathName, variableNameStartIndex, variable); + if (!addSuccess) + { + WARNING(true, ("addVariableTakeOwnership(): failed to add variable [%s] to directory for [%s].\n", fullVariablePathName.c_str() + variableNameStartIndex, fullVariablePathName.c_str())); + delete variable; + return; + } + + //-- set the variable's owner + variable->setOwner(this); +} + +// ---------------------------------------------------------------------- + +const CustomizationVariable *CustomizationData::findConstVariable(const std::string &fullVariablePathName) const +{ + //-- find the directory which owns this variable. + const bool traverseRemoteDirectories = true; + int variableNameStartIndex = 0; + + const Directory *const targetDirectory = findConstDirectoryFromPathName(fullVariablePathName, traverseRemoteDirectories, variableNameStartIndex); + if (!targetDirectory) + return 0; + + //-- find the variable + return targetDirectory->findConstVariable(fullVariablePathName, variableNameStartIndex); +} + +// ---------------------------------------------------------------------- + +CustomizationVariable *CustomizationData::findVariable(const std::string &fullVariablePathName) +{ + //-- find the directory which owns this variable. + const bool createLocalMissingDirectories = true; + const bool traverseRemoteDirectories = true; + int variableNameStartIndex = 0; + + Directory *const targetDirectory = findDirectoryFromPathName(fullVariablePathName, traverseRemoteDirectories, createLocalMissingDirectories, variableNameStartIndex); + if (!targetDirectory) + return 0; + + //-- find the variable + return targetDirectory->findVariable(fullVariablePathName, variableNameStartIndex); +} + +// ---------------------------------------------------------------------- +/** + * Iterate over a const version of each CustomizationVariable. + * + * This function will call the specified callback, passing in the context + * and the next CustomizationVariable with each callback invocation. + * + * @param callback this callback function will be invoked once per + * CustomizationVariable. + * @param context this is the context passed to the callback function. + * @param includeRemoteVariables if true, remote (mounted) CustomizationData varaibles + * will be iterated over as well as local variables. + */ + +void CustomizationData::iterateOverConstVariables(ConstIteratorCallback callback, void *context, bool includeRemoteVariables) const +{ + NOT_NULL(callback); + m_rootDirectory->iterateOverConstVariables(std::string("/"), callback, context, includeRemoteVariables); +} + +// ---------------------------------------------------------------------- +/** + * Iterate over a modifiable version of each CustomizationVariable. + * + * This function will call the specified callback, passing in the context + * and the next CustomizationVariable with each callback invocation. + * + * @param callback this callback function will be invoked once per + * CustomizationVariable. + * @param context this is the context passed to the callback function. + * @param includeRemoteVariables if true, remote (mounted) CustomizationData varaibles + * will be iterated over as well as local variables. + */ + +void CustomizationData::iterateOverVariables(IteratorCallback callback, void *context, bool includeRemoteVariables) +{ + NOT_NULL(callback); + m_rootDirectory->iterateOverVariables(std::string("/"), callback, context, includeRemoteVariables); +} + +// ---------------------------------------------------------------------- + +/** + * Mount a directory tree of a remote CustomizationData instance to show up in + * this CustomizationData instance at a specified directory. + * + * If the local mount point directory already exists, it and its contents will + * be deleted when the remote directory is mounted. + * + * @param localDirectory the directory name within the local CustomizationData + * where the remote CustomizationData directory should + * appear. This string should not end in a foward slash. + * Do not try to mount a remote directory as the root + * directory. + * + * @return true if the remote CustomizationData was attached successfully; + * false otherwise. + */ + +bool CustomizationData::mountRemoteCustomizationData(CustomizationData &customizationDataToAttach, const std::string &remoteDirectoryPath, const std::string &localDirectoryPath, bool nonExistentLeafDirectoryOk) +{ + //-- find the local directory to which we'll be mounting the remote directory as a subdirectory. + int subdirectoryNameStartIndex = 0; + const bool traverseRemoteDirectories = false; + const bool createLocalMissingDirectories = true; + + Directory *const localParentDirectory = findDirectoryFromPathName(localDirectoryPath, traverseRemoteDirectories, createLocalMissingDirectories, subdirectoryNameStartIndex); + if (!localParentDirectory) + { + WARNING(true, ("mountRemoteCustomizationData(): failed to resolve full localDirectoryPath pathname [%s] to local customization directory.\n", localDirectoryPath.c_str())); + return false; + } + + //-- get the remote target Directory instance we're mounting. + int targetNameStartIndex = 0; + const bool targetTraverseRemoteDirectories = true; + const bool targetCreateLocalMissingDirectories = false; + + // ensure target directory ends in a forward slash --- we want to resolve the whole thing. + Directory *targetDirectory; + + const bool hasEndingSlash = (!remoteDirectoryPath.empty() && (remoteDirectoryPath[remoteDirectoryPath.length()-1] == '/')); + if (hasEndingSlash) + { + // use remote directory name as is + targetDirectory = customizationDataToAttach.findDirectoryFromPathName(remoteDirectoryPath, targetTraverseRemoteDirectories, targetCreateLocalMissingDirectories, targetNameStartIndex); + } + else + { + // add ending slash to remote directory name + std::string realTargetDirectoryPath = remoteDirectoryPath; + realTargetDirectoryPath += '/'; + + targetDirectory = customizationDataToAttach.findDirectoryFromPathName(realTargetDirectoryPath, targetTraverseRemoteDirectories, targetCreateLocalMissingDirectories, targetNameStartIndex); + } + + if (!targetDirectory) + { + if (!nonExistentLeafDirectoryOk) + { + // WARNING(true, ("mountRemoteCustomizationData([%s]) on [%s]: remote directory [%s] does not exist", myAppearanceTemplateName, attachAppearanceTemplateName, remoteDirectoryPath.c_str())); + WARNING(true, ("designer bug: /shared_owner/ customization data missing for object template [%s].", customizationDataToAttach.getOwnerObject().getObjectTemplateName())); +#ifdef _DEBUG + if (ConfigSharedObject::getLogCustomizationDataIssues()) + { + DEBUG_REPORT_LOG(true, ("CustomizationData dump for object template [%s] (cd client):\n", m_owner.getObjectTemplateName())); + debugDump(); + + DEBUG_REPORT_LOG(true, ("CustomizationData dump for object template [%s] (cd server):\n", customizationDataToAttach.getOwnerObject().getObjectTemplateName())); + customizationDataToAttach.debugDump(); + } +#endif + } + return false; + } + + //-- create the RemoteDirectory node that points to the target directory + Directory *const remoteDirectory = new RemoteDirectory(customizationDataToAttach, *this, *targetDirectory); + + //-- perform the attachment operation + localParentDirectory->replaceOrAddDirectory(localDirectoryPath, subdirectoryNameStartIndex, remoteDirectory); + + //-- signal to this container that a change occurred (or at least, in theory, could have occurred). + // When we attach/detach a parent, we change the view of variables available to this CustomizationData. + signalModified(); + + //-- return success + return true; //lint !e429 // custodial pointer 'remoteDirectory' not freed or returned // ownership transferred +} + +// ---------------------------------------------------------------------- +/** + * Remove a previously mounted remote directory from this CustomizationData + * instance. + * + * @param localDirectoryPathName the full pathname of the local directory + * currently mounted. Do not include a + * trailing slash (directory separator). + * + * @return true if the remote CustomizationData was detached successfully; + * false otherwise. + */ + +bool CustomizationData::dismountRemoteCustomizationData(const std::string &localDirectoryPathName, bool nonExistentLeafDirectoryOk) +{ + //-- ensure there isn't an ending slash + const bool hasEndingSlash = (!localDirectoryPathName.empty() && localDirectoryPathName[localDirectoryPathName.length()-1] == '/'); + if (hasEndingSlash) + { + WARNING(true, ("dismountRemoteCustomizationData(): localDirectoryPathName arg [%s] must not have a trailing directory separator]", localDirectoryPathName.c_str())); + return false; + } + + //-- find the local directory + int subdirectoryNameStartIndex = 0; + const bool traverseRemoteDirectories = false; + const bool createLocalMissingDirectories = false; + + Directory *const parentDirectory = findDirectoryFromPathName(localDirectoryPathName, traverseRemoteDirectories, createLocalMissingDirectories, subdirectoryNameStartIndex); + if (!parentDirectory) + { + WARNING(true, ("dismountRemoteCustomizationData(): local parent of directory [%s] does not exist", localDirectoryPathName.c_str())); + return false; + } + + //-- ensure the directory is a remote directory + Directory *const baseRemoteDirectory = parentDirectory->findDirectory(localDirectoryPathName, subdirectoryNameStartIndex); + if (!baseRemoteDirectory) + { + WARNING(!nonExistentLeafDirectoryOk, ("dismountRemoteCustomizationData(): leaf directory [%s] does not exist.", localDirectoryPathName.c_str())); + return false; + } + + RemoteDirectory *const remoteDirectory = dynamic_cast(baseRemoteDirectory); + if (!remoteDirectory) + { + WARNING(true, ("dismountRemoteCustomizationData(): directory [%s] exists but is not a mounted directory.", localDirectoryPathName.c_str())); + return false; + } + + //-- delete the remote directory entry from the parent + parentDirectory->deleteDirectory(remoteDirectory); + + //-- return success + return true; +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the owner CustomizationData instance for the variables in the given + * directory. + * + * The CustomizationData instance returned will be the CustomizationData instance + * that persists (or are local to) the variables in the directory. When the + * variables are local to this CustomizationData instance, this instance is returned. + * When the directory is mounted from another CustomizationData instance, the server + * CustomizationData instance for the mount is returned. + * + * This function is useful to wearables that need to traverse to the owner Object. + * The wearable can traverse to the CustomizationData instance for the /shared_owner + * directory, and from there can get the owner Object instance. + * + * @param directory the directory containing variables that are persisted by the + * CustomzationData instance returned by this function. This directory + * should contain a trialing directory separator. + * + * @return the CustomizationData instance that persists the variables in the given + * directory. + */ + +const CustomizationData *CustomizationData::getDirectoryOwner(const std::string &directory) const +{ + //-- Ensure there is an ending slash. + const bool hasEndingSlash = (!directory.empty() && directory[directory.length()-1] == '/'); + if (!hasEndingSlash) + { + DEBUG_WARNING(true, ("getDirectoryOwner(): directory arg [%s] must have a trailing directory separator].", directory.c_str())); + return 0; + } + + //-- Find the directory. + int subdirectoryNameStartIndex = 0; + const bool traverseRemoteDirectories = true; + + const Directory *const parentDirectory = findConstDirectoryFromPathName(directory, traverseRemoteDirectories, subdirectoryNameStartIndex); + if (!parentDirectory) + { + DEBUG_WARNING(ConfigSharedObject::getLogCustomizationDataIssues(), ("getDirectoryOwner(): directory [%s] does not exist.", directory.c_str())); +#ifdef _DEBUG + if (ConfigSharedObject::getLogCustomizationDataIssues()) + debugDump(); +#endif + return 0; + } + + //-- Return the owner CustomizationData instance for the directory. + return &(parentDirectory->getOwner()); +} + +// ---------------------------------------------------------------------- + +std::string CustomizationData::writeLocalDataToString() const +{ + //-- Save binary version of state into byte buffer. + ByteVector binaryData; + + saveToByteVector(binaryData); + + //-- Convert binary data to string. We're escaping the 0 for the database so this is a non-null string. + // We translate 0x00 => 0xff 0x01 + // 0xff => 0xff 0x02 + std::string returnValue; + + returnValue.reserve(static_cast(static_cast(binaryData.size()) * 1.25f)); + + ByteVector::iterator const endIt = binaryData.end(); + for (ByteVector::iterator it = binaryData.begin(); it != endIt; ++it) + { + byte const value = *it; + switch (value) + { + case 0: + returnValue.push_back(static_cast(-1)); + returnValue.push_back(0x01); + break; + + case 0xff: + returnValue.push_back(static_cast(-1)); + returnValue.push_back(0x02); + break; + + default: + returnValue.push_back(static_cast(value)); + } + } + + // Append non-space end-of-data escape sequence so database doesn't truncate trailing values that just happen to be whitespace. + returnValue.push_back(static_cast(-1)); + returnValue.push_back(static_cast(3)); + + // We need our string to be a compatible utf8 string + // so convert our narrow string to a wide string and + // then to a utf8 string + return Unicode::wideToUTF8( Unicode::narrowToWide( returnValue ) ); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::loadLocalDataFromString(const std::string &stringData) +{ + // The first byte of the data is the version number and fortunately + // it is also the the first byte of the string + if (stringData.size() > 0 ) + { + std::string::value_type const version = stringData[0]; + switch (version) + { + case 1: + loadLocalDataFromString_1(stringData); + break; + + case 2: + loadLocalDataFromString_2(stringData); + break; + + default: + { + Object const &object = getOwnerObject(); + WARNING(true, ("object id [%s], template [%s] tried to load local data from string from unsupported version [%d].", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), static_cast(version))); + } + } + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::loadLocalDataFromString_1(const std::string &stringData) +{ + Object const &object = getOwnerObject(); + + //-- Convert string to binary ByteVector. + // We translate 0xff 0x01 => 0x00 + // 0xff 0x02 => 0xff + ByteVector binaryData; + + binaryData.reserve(stringData.size()); + + std::string::const_iterator const endIt = stringData.end(); + for (std::string::const_iterator it = stringData.begin(); it != endIt; ++it) + { + std::string::value_type const character = *it; + switch (character) + { + case static_cast(-1): + { + //-- Handle escaped data. + std::string::const_iterator nextIt = it + 1; + if (nextIt == endIt) + { + WARNING(true, ("object id [%s], template [%s]: corrupt customization data, unexpected end of data, invalid string form [%s].", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), stringData.c_str())); + + std::string const corruptDataDump = CustomizationData::makeSelectDumpFormat(stringData.c_str()); + LOG("customization-data-loss", ("corrupt encoded data (expecting escaped char) for id=[%s],template=[%s], corrupt data in SELECT DUMP format:[%s]", getOwnerObject().getNetworkId().getValueString().c_str(), getOwnerObject().getObjectTemplateName(), corruptDataDump.c_str())); + return; + } + else + { + std::string::value_type const nextCharacter = *nextIt; + switch (nextCharacter) + { + case 0x01: + // This is an escaped 0x00. + binaryData.push_back(0x00); + + // Consume the character. + ++it; + break; + + case 0x02: + // This is an escaped 0xff. + binaryData.push_back(0xff); + + // Consume the character. + ++it; + break; + + case 0x03: + { + // This marks the end of data. + std::string::const_iterator finalIt = nextIt + 1; + WARNING(finalIt != endIt, ("object id [%s], template [%s]: corrupt customization data, found end-of-data escape sequence while not at end of data, invalid string form [%s], ignoring.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), stringData.c_str())); + + // Consume the character. + ++it; + } + break; + + default: + WARNING(true, ("object id [%s], template [%s]: corrupt customization data, unsupported escape character ord=[%d], invalid string form [%s].", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), static_cast(nextCharacter), stringData.c_str())); + + std::string const corruptDataDump = CustomizationData::makeSelectDumpFormat(stringData.c_str()); + LOG("customization-data-loss", ("corrupt encoded data (unsupported escaped char: ord=%d) for id=[%s],template=[%s],corrupt data in SELECT DUMP format:[%s]", static_cast(nextCharacter), getOwnerObject().getNetworkId().getValueString().c_str(), getOwnerObject().getObjectTemplateName(), corruptDataDump.c_str())); + return; + } + } + break; + } + + default: + //-- Handle unescaped data. + binaryData.push_back(static_cast(character)); + } + } + + //-- Restore state from binary data. + bool const restoreResult = restoreFromByteVector(binaryData); + WARNING(!restoreResult, ("object id [%s], template [%s]: customization data restore error!", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::loadLocalDataFromString_2(const std::string &stringData) +{ + // Version 2 of the data has the string encoded as utf8 + loadLocalDataFromString_1( Unicode::wideToNarrow( Unicode::utf8ToWide( stringData ) ) ); +} + +// ---------------------------------------------------------------------- +/** + * Registers a callback that will be invoked whenever a modification is + * made to a variable of this instance. + * + * The callback will be invoked whenever a variable local to this + * CustomizationData instance is modified. In addition, the callback + * will be invoked whenever a mounted CustomizationData instance is + * modified. + * + * @param modificationCallback callback function to invoke after variables + * are modified. + * @param context context value that will be passed to the + * callback whenever the callback is invoked. + * This instance will never modify the context. + */ + +void CustomizationData::registerModificationListener(ModificationCallback modificationCallback, const void *context) +{ + m_modificationCallbacks->push_back(ModificationCallbackData(modificationCallback, context)); +} + +// ---------------------------------------------------------------------- +/** + * Remove the registration of a modification callback previously made + * via registerModificationListener(). + * + * The caller should use this function to suppress future modification + * notification callbacks to a given callback/context combination. + * + * The caller must provide the identical callback function and context + * in order to deregister it. + * + * @param modificationCallback callback function to remove. + * @param context context associated with callback function + * to remove. + */ + +void CustomizationData::deregisterModificationListener(ModificationCallback modificationCallback, const void *context) +{ + //-- find the specified callback + ModificationCallbackDataVector::iterator findIt = std::find(m_modificationCallbacks->begin(), m_modificationCallbacks->end(), ModificationCallbackData(modificationCallback, context)); + if (findIt == m_modificationCallbacks->end()) + { + WARNING(true, ("specified callback/context pair not registered [0x%08x/0x%08x]", modificationCallback, context)); + return; + } + + //-- erase the callback + IGNORE_RETURN(m_modificationCallbacks->erase(findIt)); +} + +// ---------------------------------------------------------------------- +/** + * Notifies this CustomizationData instance that a local variable has + * been modified. + * + * Only CustomizationVariable-derived classes should need to call this. + */ + +void CustomizationData::signalModified() const +{ + //-- call all modification functions + { + const ModificationCallbackDataVector::iterator endIt = m_modificationCallbacks->end(); + for (ModificationCallbackDataVector::iterator it = m_modificationCallbacks->begin(); it != endIt; ++it) + { + // invoke the callback + (*(it->m_callback))(*this, it->m_context); + } + } + + //-- propagate modification signal to all CustomizationData instances + // that have mounted this CustomizationData instance. + if (m_dependentCustomizationDataMap) + { + const CustomizationDataIntMap::iterator endIt = m_dependentCustomizationDataMap->end(); + for (CustomizationDataIntMap::iterator it = m_dependentCustomizationDataMap->begin(); it != endIt; ++it) + { + // signal the dependent CustomizationData + it->first->signalModified(); + } + } +} + +// ---------------------------------------------------------------------- +/** + * Decrement the reference count associated with the CustomizationData + * instance. + * + * The user should fetch() a reference for each logical reference the + * user makes to the CustomizationData instance. When a logical reference + * no longer is needed, the caller should call release(). + * + * When the reference count reaches zero, the CustomizationData will + * be destroyed. + * + * @see CustomizationData::release() + */ + +void CustomizationData::release() const +{ + --m_referenceCount; + if (m_referenceCount < 1) + { + DEBUG_FATAL(m_referenceCount < 0, ("bad reference counting code, releasing dead object")); + delete const_cast(this); + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::alterLocalVariables() +{ + iterateOverVariables(alterVariableCallback, this, false); +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +/** + * Log a dump of all variables accessible via this CustomizationData instance. + */ + +void CustomizationData::debugDump() const +{ + DEBUG_REPORT_LOG(true, ("BEGIN: CustomizationData debugDump\n")); + + iterateOverConstVariables(debugDumpIterationCallback, 0); + + DEBUG_REPORT_LOG(true, ("END: CustomizationData debugDump\n")); +} + +#endif + +// ====================================================================== + +void CustomizationData::remove() +{ + DEBUG_FATAL(!ms_installed, ("CustomizationData not installed.")); + ms_installed = false; + + removeMemoryBlockManager(); +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void CustomizationData::debugDumpIterationCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context) +{ + UNREF(context); + NOT_NULL(customizationVariable); + + DEBUG_REPORT_LOG(true, (" %s: %s\n", fullVariablePathName.c_str(), customizationVariable->debugToString().c_str())); +} + +#endif + +// ====================================================================== + +CustomizationData::~CustomizationData() +{ + //-- tell any CustomizationData instances dependent on this one that this + // instance is dying. Allow those instances to destroy any remote directories + // attached to this one. + if (m_dependentCustomizationDataMap) + { + // note: the underlying map will be modified during loop iterations. I'm not + // 100% certain in node-based structures if I can count on the end() value staying + // constant while map entries are deleted. If this section ever causes problems, remove + // the const endIt and replace the loop test with a call to the end() function call. + const CustomizationDataIntMap::iterator endIt = m_dependentCustomizationDataMap->end(); + for (CustomizationDataIntMap::iterator it = m_dependentCustomizationDataMap->begin(); it != endIt;) + { + // preserve looping iterator since notifyPendingRemoteDestruction() will destroy its associated iterator. + CustomizationDataIntMap::iterator oldIt = it; + ++it; + + oldIt->first->notifyPendingRemoteDestruction(this); + } + + delete m_dependentCustomizationDataMap; + } + + delete m_modificationCallbacks; + delete m_rootDirectory; +} + +// ---------------------------------------------------------------------- +/** + * Identical to findDirectoryFromPathName(), except you can never create + * local missing directories. + * + * @see CustomizationData::findDirectoryFromPathName() + */ + +const CustomizationData::Directory *CustomizationData::findConstDirectoryFromPathName(const std::string &variablePathName, bool traverseRemoteDirectories, int &directoryEntryStartIndex) const +{ + //-- check for zero-length path name + if (variablePathName.empty()) + { + WARNING(true, ("findDirectoryFromVariablePath() called with empty variablePathName name.")); + return 0; + } + + //-- all directories are assumed to be relative to root. There is no current directory + // concept. CustomizationData accepts both "/subdir1/variable1" and "subdir1/variable1" + // as starting at the root directory. + const int pathStartIndex = (variablePathName[0] == '/') ? 1 : 0; + + //-- find the directory referenced by the path name. + const bool createMissingLocalDirectories = false; + Directory *targetDirectory = 0; + + const bool resolveSuccess = m_rootDirectory->resolvePathNameToDirectory(variablePathName, pathStartIndex, traverseRemoteDirectories, createMissingLocalDirectories, targetDirectory, directoryEntryStartIndex); + if (resolveSuccess) + return targetDirectory; + else + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Find the Directory instance and the start of the path name directory + * entry from a full path name. + * + * Path names are of the form /xxx/yyy/zzz or xxx/yyy/zzz, where + * xxx and yyy represent a hierarchical directory structure and zzz + * represents an entry in the "/xxx/yyy/" subdirectory tree. zzz may + * be either a variable entry or another subdirectory entry. The + * directory structure may be as deep as the caller desires. + * + * If the caller wants /xxx/yyy/ returned as the directory, and the start + * of zzz returned as the directory entry, then zzz must not end in + * the forward slash. If it did end in a forward slash, then the + * directory "/xxx/yyy/zzz" would be returned with the directory entry + * name starting at the end of the string (i.e. nothing). + * + * Intermediate missing local directories can be created as an option. + * Remote directories will never be created. + * + * Optionally the Directory search can suppress traversal of remote + * links. + */ + +CustomizationData::Directory *CustomizationData::findDirectoryFromPathName(const std::string &variablePathName, bool traverseRemoteDirectories, bool createLocalMissingDirectories, int &directoryEntryStartIndex) +{ + //-- check for zero-length path name + if (variablePathName.empty()) + { + WARNING(true, ("findDirectoryFromVariablePath() called with empty variablePathName name.")); + return 0; + } + + //-- all directories are assumed to be relative to root. There is no current directory + // concept. CustomizationData accepts both "/subdir1/variable1" and "subdir1/variable1" + // as starting at the root directory. + const int pathStartIndex = (variablePathName[0] == '/') ? 1 : 0; + + //-- find the directory referenced by the path name. + Directory *targetDirectory = 0; + + const bool resolveSuccess = m_rootDirectory->resolvePathNameToDirectory(variablePathName, pathStartIndex, traverseRemoteDirectories, createLocalMissingDirectories, targetDirectory, directoryEntryStartIndex); + if (resolveSuccess) + return targetDirectory; + else + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Indicate the given CustomizationData instance has a dependency on this + * CustomizationData instance. + * + * When another CustomizationData instance has a dependency on this + * CustomizationData instance, the other instance will receive a + * signalModified() invocation whenever any variables associated with + * this instance are modified. Also, if this CustomizationData instance + * is destroyed, all dependencent instances will receive a + * notifyPendingRemoteDestruction() invocation prior to this instance destruction. + * This hook allows dependent CustomizationData instances to remove + * remote links to this dying instance. + * + * A dependent CustomizationData instance must unhook itself from + * this instance prior the dependent's destruction via a call to + * removeDependentCustomizationData. + * + * A reference count is associated with each CustomizationData since + * it is entirely legal for multiple directories on one instance to + * mount to multiple remote directories on another instance. The depends-on + * link is only broken once the reference count is decremented to zero. + * Each call to addDependentCustomizationData() requires a matching call to + * removeDependentCustomizationData(). + * + * @param customizationData the CustomizationData instance dependent + * on this instance. + * + * @see removeDependentCustomizationData() + * @see notifyPendingRemoteDestruction() + */ + +void CustomizationData::addDependentCustomizationData(CustomizationData *customizationData) +{ + //-- ensure the dependent CustomizationData map exists + if (!m_dependentCustomizationDataMap) + m_dependentCustomizationDataMap = new CustomizationDataIntMap(); + + //-- determine if an entry for the dependent customizationData exists + CustomizationDataIntMap::iterator lowerBoundResult = m_dependentCustomizationDataMap->lower_bound(customizationData); + const bool entryExists = ((lowerBoundResult != m_dependentCustomizationDataMap->end()) && !m_dependentCustomizationDataMap->key_comp()(customizationData, lowerBoundResult->first)); + + if (!entryExists) + { + // create entry, set reference count to 1 + IGNORE_RETURN(m_dependentCustomizationDataMap->insert(lowerBoundResult, CustomizationDataIntMap::value_type(customizationData, 1))); + } + else + { + // entry exists, bump up reference count. + ++(lowerBoundResult->second); + } +} + +// ---------------------------------------------------------------------- +/** + * Indicate the given CustomizationData instance had a dependency on this + * CustomizationData instance, but no longer requires it. + * + * A dependent CustomizationData instance must unhook itself from + * this instance prior the dependent's destruction. + * + * A reference count is associated with each CustomizationData since + * it is entirely legal for multiple directories on one instance to + * mount to multiple remote directories on another instance. The depends-on + * link is only broken once the reference count is decremented to zero. + * Each call to addDependentCustomizationData() requires a matching call to + * removeDependentCustomizationData(). + * + * @param customizationData the CustomizationData instance formerly dependent + * on this instance. + * + * @see addDependentCustomizationData() + * @see notifyPendingRemoteDestruction() + */ + +void CustomizationData::removeDependentCustomizationData(CustomizationData *customizationData) +{ + bool hasEntry = false; + + if (m_dependentCustomizationDataMap) + { + //-- find the customization data entry + CustomizationDataIntMap::iterator findIt = m_dependentCustomizationDataMap->find(customizationData); + if (findIt != m_dependentCustomizationDataMap->end()) + { + //-- decrement reference count on the specified customizationData. + --(findIt->second); + + //-- check for removal of entry + if (findIt->second < 1) + m_dependentCustomizationDataMap->erase(findIt); + + //-- indicate we found the entry. + hasEntry = true; + } + } + + WARNING(!hasEntry, ("removeDependentCustomizationData(): customizationData [0x%08x] not dependent on this instance.", customizationData)); +} + +// ---------------------------------------------------------------------- +/** + * Indicates the given CustomizationData instance argument, on which the called + * instance is dependent, is about to be destroyed. + * + * This function allows a CustomizationData instance dependent on another instance + * to remove any remote links to the about-to-be-destroyed instance. + * + * @param customizationData the instance that is about to die, and which the called + * instance is dependent on. + */ + +void CustomizationData::notifyPendingRemoteDestruction(const CustomizationData *customizationData) +{ + //-- validate arg + if (!customizationData) + { + DEBUG_WARNING(true, ("notifyPendingRemoteDestruction(): customizationData arg is null")); + return; + } + + //-- delete any directory that links to the specified customization data. + m_rootDirectory->deleteLinksTo(*customizationData); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::saveToByteVector(ByteVector &data, bool persistRemoteData) const +{ + //-- Collect all persistable customization variables. + CustomizationVariableConstVector variables; + iterateOverConstVariables(collectPersistedVariablesCallback, &variables, persistRemoteData); + + //-- Write header data. + // version 1. + data.push_back(2); + + // Write # variables. + int const variableCount = static_cast(variables.size()); + FATAL(variableCount > 255, ("CustomizationData persistence format must be upgraded. version 1 only supports 255 persisted variables but object id [%s] has %d variables.", getOwnerObject().getNetworkId().getValueString().c_str(), variableCount)); + data.reserve(static_cast(3 + variableCount * 2)); + data.push_back(static_cast(variableCount)); + + //-- Write per-variable data. + for (int i = 0; i < variableCount; ++i) + { + CustomizationVariable const *variable = variables[static_cast(i)].second; + NOT_NULL(variable); + + std::string const &variableName = variables[static_cast(i)].first; + DEBUG_FATAL(variableName.length() < 1, ("zero-length variable name: logic error.")); + + // Lookup variable id from name. + int variableId = -1; + bool const mapSuccessful = CustomizationIdManager::mapStringToId(variableName.c_str(), variableId); + + FATAL(!mapSuccessful, ("object id [%s] failed to map customization variable name [%s] to a customization variable id. Somebody forgot to run the customization id update process. Will not try to save incomplete data.", getOwnerObject().getNetworkId().getValueString().c_str(), variableName.c_str())); + DEBUG_FATAL((variableId < 0) || (variableId >= 128), ("logic error: CustomizationIdManager returned an out-of-range value [%d] for customization data format 0.", variableId)); + + // Find out if variable is stored as 1 byte unsigned or 2 byte signed. + int const persistedDataSize = variable->getPersistedDataByteCount(); + VALIDATE_RANGE_INCLUSIVE_INCLUSIVE(1, persistedDataSize, 2); + + //-- Write variable declaration. + byte combinedId = static_cast(variableId); + if (persistedDataSize == 2) + combinedId |= 0x80; + + data.push_back(combinedId); + + //-- Write variable data. + variable->saveToByteVector(data); + } +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::restoreFromByteVector(ByteVector const &data) +{ + Object const &object = getOwnerObject(); + + //-- Check for no data. + if (data.empty()) + { + WARNING(true, ("object id [%s], template [%s] tried to restore customization data from zero-length customization data.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); + return false; + } + + //-- Get version number. + bool returnValue = false; + + byte const version = data.front(); + switch (version) + { + case 1: + returnValue = restoreFromByteVector_1(data); + break; + + case 2: + returnValue = restoreFromByteVector_2(data); + break; + + default: + { + WARNING(true, ("object id [%s], template [%s] tried to restore customization data from unsupported version [%d].", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), static_cast(version))); + returnValue = false; + } + } + + //-- Signal that we are modified. + if (returnValue) + signalModified(); + + return returnValue; +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::restoreFromByteVector_1(ByteVector const &data) +{ + Object const &object = getOwnerObject(); + + //-- Verify data contains a variable count. + int const dataSize = static_cast(data.size()); + if (dataSize < 2) + { + WARNING(true, ("object id [%s], template [%s] tried to restore customization data from corrupt customization data version 1.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); + return false; + } + + //-- Get variable count. + int const variableCount = static_cast(data[1]); + int const minPossibleDataSize = 2 + variableCount * 2; + if (dataSize < minPossibleDataSize) + { + WARNING(true, ("object id [%s], template [%s] customization data corrupted: must be at least [%d] bytes for [%d] variables but only contains [%d] bytes.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), minPossibleDataSize, variableCount, dataSize)); + return false; + } + + bool result = true; + + //-- Process each variable. + int currentIndex = 2; + std::string variableName; + + for (int i = 0; i < variableCount; ++i) + { + // Get combined variable id. + byte const combinedVariableId = data[static_cast(currentIndex)]; + ++currentIndex; + + // Extract high-bit to determine if variable is interpreted as 2-byte (signed) or 1-byte (unsigned), + // extract lower 7 bits for variable id. + int const variableSize = ((combinedVariableId & 0x80) != 0) ? 2 : 1; + int const variableId = combinedVariableId & 0x7f; + + // Lookup variable name. + bool const foundMapping = CustomizationIdManager::mapIdToString(variableId, variableName); + if (!foundMapping) + { + WARNING(true, ("object id [%s], template [%s] references unmapped variable, id=[%d], variable size = [%d], aborting load.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), variableId, variableSize)); + result = false; + return false; + } + + // Get variable for name. + CustomizationVariable *const variable = findVariable(variableName); + if (!variable) + { + WARNING(true, ("object id [%s], template [%s] references undeclared variable [%s], ignoring variable.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), variableName.c_str())); + currentIndex += variableSize; + result = false; + continue; + } + + // Let variable load the data. + bool const restoreSuccess = variable->restoreFromByteVector(data, currentIndex, variableSize); + if (!restoreSuccess) + { + WARNING(true, ("object id [%s], template [%s] references customization variable [%s]; data restoration failed.", object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), variableName.c_str())); + result = false; + return false; + } + + // Move past data. + currentIndex += variableSize; + } + + return result; +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::restoreFromByteVector_2(ByteVector const &data) +{ + // The binary representation hasn't changed between versions 1 & 2. + // Only the string representation has changed because of an utf8 issue + // (we use utf8 to store the string in an objvar but the version 1 + // string had "characters" that were incompatible with utf8) + return restoreFromByteVector_1(data); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.h new file mode 100644 index 00000000..5188d706 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData.h @@ -0,0 +1,214 @@ +// ====================================================================== +// +// CustomizationData.h +// Copyright 2002, 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationData_H +#define INCLUDED_CustomizationData_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" + +class CrcLowerString; +class CustomizationVariable; +class Object; + +// ====================================================================== +/** + * Provides access to customization data. + * + * Typically a CustomizationData instance is embedded in a + * CustomizationDataProperty. That property is attached to + * an Object instance. + * + * Appearance-derived classes make use of the CustomizationData to + * customize the look of an appearance based on the values of customization + * variables. + * + * CustomizationData variables resides in a directory structure much like a + * Unix filesystem. A CustomizationData instance can mount the directory + * of another CustomizationData instance. The mounting feature is used by + * wearables to grab the body size customization variables from the current + * owner of the wearable. + * + * @see CustomizationDataProperty + * @see Object + */ + +class CustomizationData +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITHOUT_INSTALL; + +public: + + class Directory; + class LocalDirectory; // should be private by mbm macros needs it to be public. + + class RemoteDirectory; // should be private by mbm macros needs it to be public. + friend class RemoteDirectory; + + + typedef void (*ModificationCallback)(const CustomizationData &customizationData, const void *context); + typedef void (*ConstIteratorCallback)(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context); + typedef void (*IteratorCallback)(const std::string &fullVariablePathName, CustomizationVariable *customizationVariable, void *context); + + typedef stdvector::fwd ByteVector; + +public: + + static void install(); + + static int parseSeparatedHexInt(const std::string &data, int startPosition, int &endPosition); + static std::string parseSeparatedString(const std::string &data, int startPosition, int &endPosition); + + static std::string makeSelectDumpFormat(char const *source); + +public: + + explicit CustomizationData(Object &owner); + + void addVariableTakeOwnership(const std::string &fullVariablePathName, CustomizationVariable *variable); + + const CustomizationVariable *findConstVariable(const std::string &fullVariablePathName) const; + CustomizationVariable *findVariable(const std::string &fullVariablePathName); + + void iterateOverConstVariables(ConstIteratorCallback callback, void *context, bool includeRemoteVariables = true) const; + void iterateOverVariables(IteratorCallback callback, void *context, bool includeRemoteVariables = true); + + bool mountRemoteCustomizationData(CustomizationData &customizationDataToAttach, const std::string &remoteDirectory, const std::string &localDirectory, bool nonExistentLeafDirectoryOk = false); + bool dismountRemoteCustomizationData(const std::string &localDirectoryPathName, bool nonExistentLeafDirectoryOk = false); + + const CustomizationData *getDirectoryOwner(const std::string &directory) const; + + std::string writeLocalDataToString() const; + void loadLocalDataFromString(const std::string &stringData); + + void registerModificationListener(ModificationCallback modificationCallback, const void *context); + void deregisterModificationListener(ModificationCallback modificationCallback, const void *context); + + void signalModified() const; + + void fetch() const; + void release() const; + int getReferenceCount() const; + + Object &getOwnerObject(); + const Object &getOwnerObject() const; + + void alterLocalVariables(); + +#ifdef _DEBUG + void debugDump() const; +#endif + +public: + + static const char cms_directorySeparator; + static const char cms_stringFieldSeparator; + + static bool ms_installed; + +private: + + struct ModificationCallbackData; + + typedef stdmap::fwd CustomizationDataIntMap; + typedef stdvector::fwd ModificationCallbackDataVector; + +private: + + static void remove(); + +#ifdef _DEBUG + static void debugDumpIterationCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context); +#endif + +private: + + ~CustomizationData(); + + const Directory *findConstDirectoryFromPathName(const std::string &variablePathName, bool traverseRemoteDirectories, int &directoryEntryStartIndex) const; + Directory *findDirectoryFromPathName(const std::string &variablePathName, bool traverseRemoteDirectories, bool createLocalMissingDirectories, int &directoryEntryStartIndex); + + void addDependentCustomizationData(CustomizationData *customizationData); + void removeDependentCustomizationData(CustomizationData *customizationData); + + void notifyPendingRemoteDestruction(const CustomizationData *customizationData); + + void loadLocalDataFromString_1(const std::string &stringData); + void loadLocalDataFromString_2(const std::string &stringData); + + void saveToByteVector(ByteVector &data, bool persistRemoteData = false) const; + + bool restoreFromByteVector(ByteVector const &data); + bool restoreFromByteVector_1(ByteVector const &data); + bool restoreFromByteVector_2(ByteVector const &data); + + + // Disabled. + CustomizationData(); + CustomizationData(const CustomizationData&); + CustomizationData &operator =(const CustomizationData&); + +private: + + mutable int m_referenceCount; + + Object &m_owner; + Directory *m_rootDirectory; + + CustomizationDataIntMap *m_dependentCustomizationDataMap; + ModificationCallbackDataVector *m_modificationCallbacks; + +}; + +// ====================================================================== +/** + * Increment the reference count associated with the CustomizationData + * instance. + * + * The user should fetch() a reference for each logical reference the + * user makes to the CustomizationData instance. When a logical reference + * no longer is needed, the caller should call release(). + * + * @see CustomizationData::release() + */ + +inline void CustomizationData::fetch() const +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- +/** + * Retrieve the reference count. + * + * @return reference count. + */ + +inline int CustomizationData::getReferenceCount() const +{ + return m_referenceCount; +} + +// ---------------------------------------------------------------------- + +inline Object &CustomizationData::getOwnerObject() +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline const Object &CustomizationData::getOwnerObject() const +{ + return m_owner; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_Directory.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_Directory.h new file mode 100644 index 00000000..fabdd186 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_Directory.h @@ -0,0 +1,92 @@ +// PRIVATE + +// ====================================================================== +// +// CustomizationData_Directory.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationData_Directory_H +#define INCLUDED_CustomizationData_Directory_H + +// ====================================================================== + +#include "sharedObject/CustomizationData.h" + +// ====================================================================== + +class CustomizationData::Directory +{ +public: + + virtual ~Directory() {} + + virtual bool resolvePathNameToDirectory(const std::string &pathName, int pathStartIndex, bool traverseRemoteDirectories, bool createLocalMissingDirectories, Directory *&directory, int &directoryEntryStartIndex) = 0; + virtual bool addVariableTakeOwnership(const std::string &fullVariablePathName, int variableNameStartIndex, CustomizationVariable *variable) = 0; + + virtual const CustomizationVariable *findConstVariable(const std::string &variablePathName, int variableNameStartIndex) const = 0; + virtual CustomizationVariable *findVariable(const std::string &variablePathName, int variableNameStartIndex) = 0; + + virtual Directory *findDirectory(const std::string &directoryPathName, int directoryNameStartIndex) = 0; + virtual void deleteDirectory(Directory *childDirectory) = 0; + + virtual void iterateOverConstVariables(const std::string &parentPathName, ConstIteratorCallback callback, void *context, bool traverseRemoteDirectories) const = 0; + virtual void iterateOverVariables(const std::string &parentPathName, IteratorCallback callback, void *context, bool traverseRemoteDirectories) = 0; + + virtual void replaceOrAddDirectory(const std::string &directoryPathName, int directoryNameStartIndex, Directory *directory) = 0; + + virtual bool linksTo(const CustomizationData &customizationData) const = 0; + virtual void deleteLinksTo(const CustomizationData &customizationData) = 0; + + virtual bool isLocalDirectory() const = 0; +#if 0 + virtual std::string writeLocalDirectoryToString() const = 0; + + virtual void loadLocalDirectoryFromString(int version, const std::string &string, int startIndex) = 0; +#endif + CustomizationData &getOwner(); + const CustomizationData &getOwner() const; + +protected: + + explicit Directory(CustomizationData &owner); + +private: + + // Disabled. + Directory(); + Directory(const Directory&); + Directory &operator =(const Directory&); + +private: + + CustomizationData &m_owner; + +}; + +// ====================================================================== + +inline CustomizationData &CustomizationData::Directory::getOwner() +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline const CustomizationData &CustomizationData::Directory::getOwner() const +{ + return m_owner; +} + +// ====================================================================== + +inline CustomizationData::Directory::Directory(CustomizationData &owner) : + m_owner(owner) +{ +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.cpp b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.cpp new file mode 100644 index 00000000..3a8422cb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.cpp @@ -0,0 +1,625 @@ +// ====================================================================== +// +// CustomizationData_LocalDirectory.cpp +// Copyright 2002, 2003 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationData_LocalDirectory.h" + +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedObject/CustomizationVariable.h" +#include "sharedObject/Object.h" + +#include +#include +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(CustomizationData::LocalDirectory, true, 0, 0, 0); + +// ====================================================================== + +CustomizationData::LocalDirectory::LocalDirectory(CustomizationData &owner) : + Directory(owner), + m_variables(), + m_directories() +{ +} + +// ---------------------------------------------------------------------- + +CustomizationData::LocalDirectory::~LocalDirectory() +{ + //-- delete the variables we own + std::for_each(m_variables.begin(), m_variables.end(), PointerDeleterPairSecond()); + + //-- delete the directories + std::for_each(m_directories.begin(), m_directories.end(), PointerDeleterPairSecond()); +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::LocalDirectory::resolvePathNameToDirectory(const std::string &pathName, int pathStartIndex, bool traverseRemoteDirectories, bool createLocalMissingDirectories, Directory *&directory, int &directoryEntryStartIndex) +{ + //-- check if there's a directory embedded in the path name + const std::string::size_type endOfDirectoryName = pathName.find(CustomizationData::cms_directorySeparator, static_cast(pathStartIndex)); + const bool hasEmbeddedDirectory = (static_cast(endOfDirectoryName) != static_cast(std::string::npos)); + + if (!hasEmbeddedDirectory) + { + // The specified pathname does not have another complete subdirectory component + // embedded within it. That indicates the given pathName refers to a directory + // entry that is a direct child of this directory. + directory = this; + directoryEntryStartIndex = pathStartIndex; + return true; + } + + //-- handle embedded directory reference + + // get a CrcLowerString for the subdirectory + const std::string subdirName = pathName.substr(static_cast(pathStartIndex), endOfDirectoryName - static_cast(pathStartIndex)); + const CrcLowerString crcSubdirName(subdirName.c_str()); + + // check if subdir exists + const DirectoryMap::iterator lowerBoundResult = m_directories.lower_bound(crcSubdirName); + const bool subdirExists = ((lowerBoundResult != m_directories.end()) && !m_directories.key_comp()(crcSubdirName, lowerBoundResult->first)); + + Directory *subdir = 0; + + // handle traversal of directory + if (subdirExists) + subdir = lowerBoundResult->second; + else + { + if (!createLocalMissingDirectories) + { + // specified subdir doesn't exist and shouldn't be created. We must bail. + return false; + } + else + { + // create the missing subdirectory + subdir = new LocalDirectory(getOwner()); + IGNORE_RETURN(m_directories.insert(lowerBoundResult, DirectoryMap::value_type(crcSubdirName, subdir))); + } + } + + //-- ensure we've got a directory + if (!subdir) + { + WARNING(true, ("resolvePathNameToDirectory(): logic failure, subdir is null")); + return false; + } + + //-- traverse the directory + return subdir->resolvePathNameToDirectory(pathName, static_cast(endOfDirectoryName) + 1, traverseRemoteDirectories, createLocalMissingDirectories, directory, directoryEntryStartIndex); +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::LocalDirectory::addVariableTakeOwnership(const std::string &fullVariablePathName, int variableNameStartIndex, CustomizationVariable *variable) +{ + //-- ensure caller passed in valid customizationVariable + if (!variable) + { + WARNING(true, ("addVariableTakeOwnership(): caller passed in NULL variable")); + return false; + } + + //-- create CrcLowerString name for variable + const std::string variableName = fullVariablePathName.substr(static_cast(variableNameStartIndex)); + const CrcLowerString crcVariableName(variableName.c_str()); + + //-- handle assigning variable to variable name + CustomizationVariableMap::iterator lowerBoundResult = m_variables.lower_bound(crcVariableName); + const bool variableExists = ((lowerBoundResult != m_variables.end()) && !m_variables.key_comp()(crcVariableName, lowerBoundResult->first)); + + if (variableExists) + { + //-- replace existing variable. This probably is in error as the caller can + // lookup a value. + WARNING(true, ("addVariableTakeOwnership(): variable %s already exists, replacing old value", crcVariableName.getString())); + delete lowerBoundResult->second; + lowerBoundResult->second = variable; + } + else + { + //-- insert new variable + IGNORE_RETURN(m_variables.insert(lowerBoundResult, CustomizationVariableMap::value_type(crcVariableName, variable))); + } + + // success + return true; +} + +// ---------------------------------------------------------------------- + +const CustomizationVariable *CustomizationData::LocalDirectory::findConstVariable(const std::string &variablePathName, int variableNameStartIndex) const +{ + const CustomizationVariable *variable = 0; + + { + //-- create CrcLowerString name for variable + const std::string variableName = variablePathName.substr(static_cast(variableNameStartIndex)); + const CrcLowerString crcVariableName(variableName.c_str()); + + //-- check if variable exists + const CustomizationVariableMap::const_iterator lowerBoundResult = m_variables.lower_bound(crcVariableName); + const bool variableExists = ((lowerBoundResult != m_variables.end()) && !m_variables.key_comp()(crcVariableName, lowerBoundResult->first)); + + if (variableExists) + variable = lowerBoundResult->second; + } + + return variable; +} + +// ---------------------------------------------------------------------- + +CustomizationVariable *CustomizationData::LocalDirectory::findVariable(const std::string &variablePathName, int variableNameStartIndex) +{ + CustomizationVariable *variable = 0; + + { + //-- create CrcLowerString name for variable + const std::string variableName = variablePathName.substr(static_cast(variableNameStartIndex)); + const CrcLowerString crcVariableName(variableName.c_str()); + + //-- check if variable exists + const CustomizationVariableMap::iterator lowerBoundResult = m_variables.lower_bound(crcVariableName); + const bool variableExists = ((lowerBoundResult != m_variables.end()) && !m_variables.key_comp()(crcVariableName, lowerBoundResult->first)); + + if (variableExists) + variable = lowerBoundResult->second; + } + + return variable; +} + +// ---------------------------------------------------------------------- + +CustomizationData::Directory *CustomizationData::LocalDirectory::findDirectory(const std::string &directoryPathName, int directoryNameStartIndex) +{ + CustomizationData::Directory *directory = 0; + + { + //-- create CrcLowerString name for directory + const std::string directoryName = directoryPathName.substr(static_cast(directoryNameStartIndex)); + const CrcLowerString crcDirectoryName(directoryName.c_str()); + + //-- check if directory exists + const DirectoryMap::iterator lowerBoundResult = m_directories.lower_bound(crcDirectoryName); + const bool directoryExists = ((lowerBoundResult != m_directories.end()) && !m_directories.key_comp()(crcDirectoryName, lowerBoundResult->first)); + + if (directoryExists) + directory = lowerBoundResult->second; + } + + return directory; +} + +// ---------------------------------------------------------------------- + +void CustomizationData::LocalDirectory::deleteDirectory(Directory *childDirectory) +{ + //-- check for null directory + if (!childDirectory) + { + WARNING(true, ("deleteDirectory(): NULL childDirectory arg")); + return; + } + + //-- find the directory map entry with the given directory + DirectoryMap::iterator it = m_directories.begin(); + const DirectoryMap::iterator endIt = m_directories.end(); + + for (; (it != endIt) && (it->second != childDirectory); ++it) + { + } + + if (it == m_directories.end()) + { + WARNING(true, ("deleteDirectory(): specified directory 0x%08x is not a child of this directory", childDirectory)); + return; + } + + //-- delete child directory + delete it->second; + m_directories.erase(it); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::LocalDirectory::iterateOverConstVariables(const std::string &parentPathName, ConstIteratorCallback callback, void *context, bool traverseRemoteDirectories) const +{ + //-- invoke callback for each variable + { + const CustomizationVariableMap::const_iterator endIt = m_variables.end(); + for (CustomizationVariableMap::const_iterator it = m_variables.begin(); it != endIt; ++it) + { + const std::string fullChildVariablePathName = parentPathName + it->first.getString(); + (*callback)(fullChildVariablePathName, it->second, context); + } + } + + //-- invoke iterator over each child directory + { + const DirectoryMap::const_iterator endIt = m_directories.end(); + for (DirectoryMap::const_iterator it = m_directories.begin(); it != endIt; ++it) + { + //-- check for null directory pointer (shouldn't happen but shouldn't FATAL) + if (!it->second) + { + WARNING(true, ("iterateOverConstVariables(): directory 0x%08x has null child directory for [%s].", this, it->first.getString())); + return; + } + + //-- build child directory name + std::string fullChildDirPathName(parentPathName); + fullChildDirPathName += it->first.getString(); + fullChildDirPathName += '/'; + + //-- instruct child to iterate over its contents + it->second->iterateOverConstVariables(fullChildDirPathName, callback, context, traverseRemoteDirectories); + } + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::LocalDirectory::iterateOverVariables(const std::string &parentPathName, IteratorCallback callback, void *context, bool traverseRemoteDirectories) +{ + //-- invoke callback for each variable + { + const CustomizationVariableMap::iterator endIt = m_variables.end(); + for (CustomizationVariableMap::iterator it = m_variables.begin(); it != endIt; ++it) + { + const std::string fullChildVariablePathName = parentPathName + it->first.getString(); + (*callback)(fullChildVariablePathName, it->second, context); + } + } + + //-- invoke iterator over each child directory + { + const DirectoryMap::iterator endIt = m_directories.end(); + for (DirectoryMap::iterator it = m_directories.begin(); it != endIt; ++it) + { + //-- check for null directory pointer (shouldn't happen but shouldn't FATAL) + if (!it->second) + { + WARNING(true, ("iterateOverConstVariables(): directory 0x%08x has null child directory for [%s].", this, it->first.getString())); + return; + } + + //-- build child directory name + std::string fullChildDirPathName(parentPathName); + fullChildDirPathName += it->first.getString(); + fullChildDirPathName += '/'; + + //-- instruct child to iterate over its contents + it->second->iterateOverVariables(fullChildDirPathName, callback, context, traverseRemoteDirectories); + } + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::LocalDirectory::replaceOrAddDirectory(const std::string &directoryPathName, int directoryNameStartIndex, Directory *directory) +{ + //-- ensure attached directory is not null + if (!directory) + { + WARNING(true, ("replaceOrAddDirectory(): directory arg is NULL")); + return; + } + + //-- create CrcLowerString name for directory + const std::string directoryName = directoryPathName.substr(static_cast(directoryNameStartIndex)); + const CrcLowerString crcDirectoryName(directoryName.c_str()); + + //-- check if directory exists + DirectoryMap::iterator lowerBoundResult = m_directories.lower_bound(crcDirectoryName); + const bool directoryExists = ((lowerBoundResult != m_directories.end()) && !m_directories.key_comp()(crcDirectoryName, lowerBoundResult->first)); + + if (!directoryExists) + { + // add new directory map entry + IGNORE_RETURN(m_directories.insert(lowerBoundResult, DirectoryMap::value_type(crcDirectoryName, directory))); + } + else + { + // check for self assignment + if (directory == lowerBoundResult->second) + { + WARNING(true, ("replaceOrAddDirectory(): attempting to replace directory [%s] with self", crcDirectoryName.getString())); + return; + } + + // delete existing directory + delete lowerBoundResult->second; + + // replace existing directory with new directory + lowerBoundResult->second = directory; + } +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::LocalDirectory::linksTo(const CustomizationData &customizationData) const +{ + UNREF(customizationData); + + //-- LocalDirectory instances never link to remote directories. + return false; +} + +// ---------------------------------------------------------------------- + +void CustomizationData::LocalDirectory::deleteLinksTo(const CustomizationData &customizationData) +{ + const DirectoryMap::iterator endIt = m_directories.end(); + for (DirectoryMap::iterator it = m_directories.begin(); it != endIt;) + { + //-- save old iterator (may be deleted), increment loop iterator. + DirectoryMap::iterator oldIt = it; + ++it; + + Directory *const directory = oldIt->second; + if (directory) + { + //-- tell the child directory to delete any links it has to the specified customization data. + directory->deleteLinksTo(customizationData); + + //-- check if child directory links to specified CustomizationData instance. If so, delete it. + if (directory->linksTo(customizationData)) + { + delete oldIt->second; + m_directories.erase(oldIt); + } + } + } +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::LocalDirectory::isLocalDirectory() const +{ + return true; +} + +// ---------------------------------------------------------------------- + +#if 0 + +std::string CustomizationData::LocalDirectory::writeLocalDirectoryToString() const +{ + char scratchBuffer[1024]; + std::string data; + + //-- count # persistable variables + int variableCount = 0; + + { + const CustomizationVariableMap::const_iterator endIt = m_variables.end(); + for (CustomizationVariableMap::const_iterator it = m_variables.begin(); it != endIt; ++it) + { + //-- verify it's a non-null variable + const CustomizationVariable *const variable = it->second; + if (variable && variable->doesVariablePersist()) + { + // we will write this variable + ++variableCount; + } + } + } + + //-- write # variables + sprintf(scratchBuffer, "%x%c", variableCount, cms_stringFieldSeparator); + data += scratchBuffer; + + //-- write each variable + { + const CustomizationVariableMap::const_iterator endIt = m_variables.end(); + for (CustomizationVariableMap::const_iterator it = m_variables.begin(); it != endIt; ++it) + { + //-- verify it's a non-null variable + const CustomizationVariable *const variable = it->second; + if (!variable) + { + WARNING(true, ("writeLocalDirectoryToString: NULL variable for [%s], skipping variable writing.")); + continue; + } + + //-- skip variables that should not be written. typically this will be constant data + // that doesn't need to be customized or transmitted/persisted. + if (!variable->doesVariablePersist()) + continue; + + //-- write variable name + data += it->first.getString(); + data += cms_stringFieldSeparator; + + //-- write variable data + // get variable content data + const std::string variableContents = variable->writeToString(); + + // write content length (we do this so we can skip a variable if its not supported at load time) + sprintf(scratchBuffer, "%x%c", variableContents.size(), cms_stringFieldSeparator); + data += scratchBuffer; + + // write variable content + data += variableContents; + } + } + + //-- get # local directories to write + int directoryCount = 0; + { + const DirectoryMap::const_iterator endIt = m_directories.end(); + for (DirectoryMap::const_iterator it = m_directories.begin(); it != endIt; ++it) + { + if (it->second && it->second->isLocalDirectory()) + ++directoryCount; + } + } + + //-- write # directories + sprintf(scratchBuffer, "%x%c", directoryCount, cms_stringFieldSeparator); + data += scratchBuffer; + + //-- write directory contents + { + const DirectoryMap::const_iterator endIt = m_directories.end(); + for (DirectoryMap::const_iterator it = m_directories.begin(); it != endIt; ++it) + { + if (it->second && it->second->isLocalDirectory()) + { + // write directory name + data += it->first.getString(); + data += cms_stringFieldSeparator; + + // get directory data contents + const std::string subdirData = it->second->writeLocalDirectoryToString(); + + // write directory data size (we do this so we can skip a directory if its not supported at load time) + sprintf(scratchBuffer, "%x%c", subdirData.size(), cms_stringFieldSeparator); + data += scratchBuffer; + + // write directory contents + data += subdirData; + } + } + } + + return data; +} + +#endif + +// ---------------------------------------------------------------------- + +#if 0 + +void CustomizationData::LocalDirectory::loadLocalDirectoryFromString(int version, const std::string &string, int startIndex) +{ + if (version == 2) + loadLocalDirectoryFromString_0002(string, startIndex); + else + WARNING(true, ("loadLocalDirectoryFromString(): unsupported version [%d]", version)); +} + +#endif + +// ====================================================================== + +#if 0 + +void CustomizationData::LocalDirectory::loadLocalDirectoryFromString_0002(const std::string &data, int startIndex) +{ + int currentPosition = startIndex; + + //-- get # variables + const int variableCount = parseSeparatedHexInt(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load variable count, aborting load.")); + return; + } + + //-- load each variable + { + for (int i = 0; i < variableCount; ++i) + { + //-- load the variable name + const std::string variableName = parseSeparatedString(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load variable name, aborting load.")); + return; + } + + //-- load the # characters in the value data + const int valueCharacterCount = parseSeparatedHexInt(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load variable data size, aborting load.")); + return; + } + + //-- find the customization variable + CustomizationVariable *const variable = findVariable(variableName, 0); + if (!variable) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): variable [%s] does not exist to be restored.", variableName.c_str())); + return; + } + else + { + //-- load the data + if (!variable->loadFromString(2, std::string(data, static_cast(currentPosition), static_cast(valueCharacterCount)))) + WARNING(true, ("loadLocalDirectoryFromString_0002(): variable [%s] failed to load.", variableName.c_str())); + } + + //-- pass the variable data + currentPosition += valueCharacterCount; + } + } + + //-- get # subdirectories + const int directoryCount = parseSeparatedHexInt(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load directory count, aborting load.")); + return; + } + + //-- load each subdirectory + { + for (int i = 0; i < directoryCount; ++i) + { + //-- load the directory name + const std::string directoryName = parseSeparatedString(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load directory name, aborting load.")); + return; + } + + //-- load the # characters in the value data + const int directoryCharacterCount = parseSeparatedHexInt(data, currentPosition, currentPosition); + if (currentPosition == static_cast(std::string::npos)) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): failed to load directory data size, aborting load.")); + return; + } + + //-- find the customization variable + Directory *const directory = findDirectory(directoryName, 0); + if (!directory) + { + WARNING(true, ("loadLocalDirectoryFromString_0002(): object id=[%s], directory [%s] does not exist to be restored.", getOwner().getOwnerObject().getNetworkId().getValueString().c_str(), directoryName.c_str())); + return; + } + else + { + //-- load the data + directory->loadLocalDirectoryFromString(2, data, currentPosition); + } + + //-- pass the variable data + currentPosition += directoryCharacterCount; + } + } +} + +#endif + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.h new file mode 100644 index 00000000..a8fba11f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_LocalDirectory.h @@ -0,0 +1,83 @@ +// PRIVATE + +// ====================================================================== +// +// CustomizationData_LocalDirectory.h +// Copyright 2002, 2003 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationData_LocalDirectory_H +#define INCLUDED_CustomizationData_LocalDirectory_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/CustomizationData_Directory.h" + +#include + +class MemoryBlockManager; + +// ====================================================================== + +class CustomizationData::LocalDirectory: public CustomizationData::Directory +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + explicit LocalDirectory(CustomizationData &owner); + virtual ~LocalDirectory(); + + virtual bool resolvePathNameToDirectory(const std::string &pathName, int pathStartIndex, bool traverseRemoteDirectories, bool createLocalMissingDirectories, Directory *&directory, int &directoryEntryStartIndex); + virtual bool addVariableTakeOwnership(const std::string &fullVariablePathName, int variableNameStartIndex, CustomizationVariable *variable); + + virtual const CustomizationVariable *findConstVariable(const std::string &variableName, int variableNameStartIndex) const; + virtual CustomizationVariable *findVariable(const std::string &variableName, int variableNameStartIndex); + + virtual Directory *findDirectory(const std::string &directoryPathName, int directoryNameStartIndex); + virtual void deleteDirectory(Directory *childDirectory); + + virtual void iterateOverConstVariables(const std::string &parentPathName, ConstIteratorCallback callback, void *context, bool traverseRemoteDirectories) const; + virtual void iterateOverVariables(const std::string &parentPathName, IteratorCallback callback, void *context, bool traverseRemoteDirectories); + + virtual void replaceOrAddDirectory(const std::string &directoryPathName, int directoryNameStartIndex, Directory *directory); + + virtual bool linksTo(const CustomizationData &customizationData) const; + virtual void deleteLinksTo(const CustomizationData &customizationData); + + virtual bool isLocalDirectory() const; +#if 0 + virtual std::string writeLocalDirectoryToString() const; + + virtual void loadLocalDirectoryFromString(int version, const std::string &string, int startIndex); +#endif + +private: + + typedef stdmap::fwd DirectoryMap; + typedef stdmap::fwd CustomizationVariableMap; + +private: + +#if 0 + void loadLocalDirectoryFromString_0002(const std::string &string, int startIndex); +#endif + + // Disabled. + LocalDirectory(); + LocalDirectory(const LocalDirectory&); + LocalDirectory &operator =(const LocalDirectory&); + +private: + + CustomizationVariableMap m_variables; + DirectoryMap m_directories; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.cpp b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.cpp new file mode 100644 index 00000000..d52cb830 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.cpp @@ -0,0 +1,194 @@ +// ====================================================================== +// +// CustomizationData_RemoteDirectory.cpp +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationData_RemoteDirectory.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" + +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(CustomizationData::RemoteDirectory, true, 0, 0, 0); + +// ====================================================================== + +CustomizationData::RemoteDirectory::RemoteDirectory(CustomizationData &remoteCustomizationData, CustomizationData &localCustomizationData, Directory &targetDirectory) : + Directory(localCustomizationData), + m_remoteCustomizationData(remoteCustomizationData), + m_targetDirectory(targetDirectory) +{ + //-- tell remote customization data (for which targetDirectory is a local directory) + // that the local customization data is dependent on it. + m_remoteCustomizationData.addDependentCustomizationData(&getOwner()); +} + +// ---------------------------------------------------------------------- + +CustomizationData::RemoteDirectory::~RemoteDirectory() +{ + //-- tell remote customization data that the local customization data + // no longer is dependent on it. + m_remoteCustomizationData.removeDependentCustomizationData(&getOwner()); +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::RemoteDirectory::resolvePathNameToDirectory(const std::string &pathName, int pathStartIndex, bool traverseRemoteDirectories, bool createLocalMissingDirectories, Directory *&directory, int &directoryEntryStartIndex) +{ + UNREF(createLocalMissingDirectories); + + //-- forward the call to the remote directory only if forwarding is permitted + if (!traverseRemoteDirectories) + return false; + else + { + // continue to allow traversal of remote directories. + // do not permit creation of missing directories once we cross a remote directory. + return m_targetDirectory.resolvePathNameToDirectory(pathName, pathStartIndex, traverseRemoteDirectories, false, directory, directoryEntryStartIndex); + } +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::RemoteDirectory::addVariableTakeOwnership(const std::string &fullVariablePathName, int variableNameStartIndex, CustomizationVariable *variable) +{ + UNREF(variableNameStartIndex); + UNREF(variable); + + WARNING(true, ("addVariableTakeOwnership([%s]): operation makes no sense on RemoteDirectory instances.", fullVariablePathName.c_str())); + return false; +} + +// ---------------------------------------------------------------------- + +const CustomizationVariable *CustomizationData::RemoteDirectory::findConstVariable(const std::string &variablePathName, int variableNameStartIndex) const +{ + UNREF(variableNameStartIndex); + + WARNING(true, ("findConstVariable([%s]): operation makes no sense on RemoteDirectory instances.", variablePathName.c_str())); + return 0; +} + +// ---------------------------------------------------------------------- + +CustomizationVariable *CustomizationData::RemoteDirectory::findVariable(const std::string &variablePathName, int variableNameStartIndex) +{ + UNREF(variableNameStartIndex); + + WARNING(true, ("findVariable([%s]): operation makes no sense on RemoteDirectory instances.\n", variablePathName.c_str())); + return 0; +} + +// ---------------------------------------------------------------------- + +CustomizationData::Directory *CustomizationData::RemoteDirectory::findDirectory(const std::string &directoryPathName, int directoryNameStartIndex) +{ + UNREF(directoryNameStartIndex); + + WARNING(true, ("findDirectory([%s]): operation makes no sense on RemoteDirectory instances.\n", directoryPathName.c_str())); + return 0; +} + +// ---------------------------------------------------------------------- + +void CustomizationData::RemoteDirectory::deleteDirectory(Directory *childDirectory) +{ + UNREF(childDirectory); + + WARNING(true, ("deleteDirectory(): operation makes no sense on RemoteDirectory instances.\n")); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::RemoteDirectory::iterateOverConstVariables(const std::string &parentPathName, ConstIteratorCallback callback, void *context, bool traverseRemoteDirectories) const +{ + if (traverseRemoteDirectories) + { + // foward the call. continue to allow traversal of remote directories. + m_targetDirectory.iterateOverConstVariables(parentPathName, callback, context, traverseRemoteDirectories); + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::RemoteDirectory::iterateOverVariables(const std::string &parentPathName, IteratorCallback callback, void *context, bool traverseRemoteDirectories) +{ + if (traverseRemoteDirectories) + { + // foward the call. continue to allow traversal of remote directories. + m_targetDirectory.iterateOverVariables(parentPathName, callback, context, traverseRemoteDirectories); + } +} + +// ---------------------------------------------------------------------- + +void CustomizationData::RemoteDirectory::replaceOrAddDirectory(const std::string &directoryPathName, int directoryNameStartIndex, Directory *directory) +{ + UNREF(directoryNameStartIndex); + + //-- indicate misuse, delete the directory so it doesn't get leaked + WARNING(true, ("replaceOrAddDirectory([%s]): operation makes no sense on RemoteDirectory instances.\n", directoryPathName.c_str())); + delete directory; +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::RemoteDirectory::linksTo(const CustomizationData &customizationData) const +{ + //-- this RemoteDirectory instance links to the specified CustomizationData instance. + return (&m_remoteCustomizationData == &customizationData); +} + +// ---------------------------------------------------------------------- + +void CustomizationData::RemoteDirectory::deleteLinksTo(const CustomizationData &customizationData) +{ + UNREF(customizationData); + + //-- RemoteDirectory doesn't propagate this call across remote boundaries. + return; +} + +// ---------------------------------------------------------------------- + +bool CustomizationData::RemoteDirectory::isLocalDirectory() const +{ + return false; +} + +// ---------------------------------------------------------------------- + +#if 0 + +std::string CustomizationData::RemoteDirectory::writeLocalDirectoryToString() const +{ + WARNING(true, ("writeLocalDirectoryToString(): operation makes no sense on RemoteDirectory instances.\n")); + return ""; +} + +#endif + +// ---------------------------------------------------------------------- + +#if 0 + +void CustomizationData::RemoteDirectory::loadLocalDirectoryFromString(int version, const std::string &string, int startIndex) +{ + UNREF(version); + UNREF(string); + UNREF(startIndex); + + WARNING(true, ("loadLocalDirectoryFromString(): operation makes no sense on RemoteDirectory instances.")); +} + +#endif + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.h new file mode 100644 index 00000000..e1d89ce7 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationData_RemoteDirectory.h @@ -0,0 +1,72 @@ +// PRIVATE + +// ====================================================================== +// +// CustomizationData_RemoteDirectory.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationData_RemoteDirectory_H +#define INCLUDED_CustomizationData_RemoteDirectory_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/CustomizationData_Directory.h" + +class MemoryBlockManager; + +// ====================================================================== + +class CustomizationData::RemoteDirectory: public CustomizationData::Directory +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + RemoteDirectory(CustomizationData &remoteCustomizationData, CustomizationData &localCustomizationData, Directory &targetDirectory); + virtual ~RemoteDirectory(); + + virtual bool resolvePathNameToDirectory(const std::string &pathName, int pathStartIndex, bool traverseRemoteDirectories, bool createLocalMissingDirectories, Directory *&directory, int &directoryEntryStartIndex); + virtual bool addVariableTakeOwnership(const std::string &fullVariablePathName, int variableNameStartIndex, CustomizationVariable *variable); + + virtual const CustomizationVariable *findConstVariable(const std::string &variablePathName, int variableNameStartIndex) const; + virtual CustomizationVariable *findVariable(const std::string &variablePathName, int variableNameStartIndex); + + virtual Directory *findDirectory(const std::string &directoryPathName, int directoryNameStartIndex); + virtual void deleteDirectory(Directory *childDirectory); + + virtual void iterateOverConstVariables(const std::string &parentPathName, ConstIteratorCallback callback, void *context, bool traverseRemoteDirectories) const; + virtual void iterateOverVariables(const std::string &parentPathName, IteratorCallback callback, void *context, bool traverseRemoteDirectories); + + virtual void replaceOrAddDirectory(const std::string &directoryPathName, int directoryNameStartIndex, Directory *directory); + + virtual bool linksTo(const CustomizationData &customizationData) const; + virtual void deleteLinksTo(const CustomizationData &customizationData); + + virtual bool isLocalDirectory() const; +#if 0 + virtual std::string writeLocalDirectoryToString() const; + + virtual void loadLocalDirectoryFromString(int version, const std::string &string, int startIndex); +#endif + +private: + + // disabled + RemoteDirectory(); + RemoteDirectory(const RemoteDirectory&); + RemoteDirectory &operator =(const RemoteDirectory&); + +private: + + CustomizationData &m_remoteCustomizationData; + Directory &m_targetDirectory; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.cpp b/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.cpp new file mode 100644 index 00000000..32208e24 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.cpp @@ -0,0 +1,222 @@ +// ====================================================================== +// +// CustomizationIdManager.cpp +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationIdManager.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedFoundation/PersistentCrcString.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedFoundation/TemporaryCrcString.h" + +#include +#include +#include +#include + +// ====================================================================== + +namespace CustomizationIdManagerNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void remove(); + + void load(Iff &iff); + void load_0001(Iff &iff); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Tag const TAG_CIDM = TAG(C,I,D,M); + Tag const TAG_DATA = TAG(D,A,T,A); + + int const cs_firstAssignedId = 1; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::vector StringVector; + typedef std::map StringIntMap; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + StringVector s_idToVariableName; + StringIntMap s_variableNameToId; + + bool s_installed; +} + +using namespace CustomizationIdManagerNamespace; + +// ====================================================================== +// namespace CustomizationIdManagerNamespace +// ====================================================================== + +void CustomizationIdManagerNamespace::remove() +{ + DEBUG_FATAL(!s_installed, ("CustomizationIdManager not installed.")); + s_installed = false; + + //-- s_idToVariableName owns the strings. Delete from here, then clean up vector. + std::for_each(s_idToVariableName.begin(), s_idToVariableName.end(), PointerDeleter()); + StringVector().swap(s_idToVariableName); + + //-- Clear out s_variableNameToId map. + s_variableNameToId.clear(); +} + +// ---------------------------------------------------------------------- + +void CustomizationIdManagerNamespace::load(Iff &iff) +{ + iff.enterForm(TAG_CIDM); + { + Tag const version = iff.getCurrentName(); + switch (version) + { + case TAG_0001: + load_0001(iff); + break; + + default: + { + char name[5]; + ConvertTagToString(version, name); + FATAL(true, ("CustomizationIdManager: unsupported data file version [%s].", name)); + } + } + } + iff.exitForm(TAG_CIDM); +} + +// ---------------------------------------------------------------------- + +void CustomizationIdManagerNamespace::load_0001(Iff &iff) +{ + iff.enterForm(TAG_0001); + { + iff.enterChunk(TAG_DATA); + { + for (int expectedId = 1; iff.getChunkLengthLeft() > 0; ++expectedId) + { + //-- Read id mapping. + char variableName[MAX_PATH]; + + int const id = static_cast(iff.read_int16()); + iff.read_string(variableName, sizeof(variableName) - 1); + + //-- Add to id->variableName vector. + FATAL(id != expectedId, ("CustomizationIdManager load error: non-consecutive ids listed: expecting [%d], found [%d] for [%s].", expectedId, id, variableName)); + FATAL(id >= 128, ("CustomizationIdManager load error: exceeded limit of supported customization variable IDs [%d] for variable [%s].", id, variableName)); + + CrcString *crcVariableName = 0; + s_idToVariableName.push_back(crcVariableName = new PersistentCrcString(variableName, true)); + + //-- Add to variableName->id map. + std::pair result = s_variableNameToId.insert(StringIntMap::value_type(crcVariableName, id)); + FATAL(!result.second, ("CustomizationIdManager: failed to insert variable name [%s], id [%d] into map. Most likely duplicate entries for variabe name.", variableName, id)); + } + } + iff.exitChunk(TAG_DATA); + } + iff.exitForm(TAG_0001); +} + +// ====================================================================== +// class CustomizationIdManager +// ====================================================================== + +void CustomizationIdManager::install(char const *dataFilename) +{ + DEBUG_FATAL(s_installed, ("CustomizationIdManager already installed.")); + + //-- Load up data. + Iff iff; + + bool const openSuccess = iff.open(dataFilename, true); + FATAL(!openSuccess, ("CustomizationIdManager: could not load initialization data file [%s], are TreeFile paths set correctly?", dataFilename)); + + load(iff); + + s_installed = true; + ExitChain::add(remove, "CustomizationIdManager"); +} + +// ---------------------------------------------------------------------- + +bool CustomizationIdManager::mapIdToString(int id, std::string &variableName) +{ + DEBUG_FATAL(!s_installed, ("CustomizationIdManager not installed.")); + + //-- Adjust id for first-assigned id offset. + id -= cs_firstAssignedId; + + //-- Handle out-of-range id. + if ((id < 0) || (id >= static_cast(s_idToVariableName.size()))) + { + // Not found. + return false; + } + + //-- Set string value. + variableName = NON_NULL(s_idToVariableName[static_cast(id)])->getString(); + return true; +} + +// ---------------------------------------------------------------------- + +bool CustomizationIdManager::mapIdToString(int id, char *variableName, int bufferLength) +{ + DEBUG_FATAL(!s_installed, ("CustomizationIdManager not installed.")); + + //-- Adjust id for first-assigned id offset. + id -= cs_firstAssignedId; + + //-- Handle out-of-range id. + if ((id < 0) || (id >= static_cast(s_idToVariableName.size()))) + { + // Not found. + return false; + } + + //-- Set string value. + NOT_NULL(variableName); + DEBUG_FATAL(bufferLength < 1, ("CustomizationIdManager: bufferLength of [%d] too small to hold anything.", bufferLength)); + + //-- Copy variable name to user buffer, ensure it gets NULL terminated. + strncpy(variableName, NON_NULL(s_idToVariableName[static_cast(id)])->getString(), static_cast(bufferLength - 1)); + variableName[bufferLength - 1] = '\0'; + + return true; +} + +// ---------------------------------------------------------------------- + +bool CustomizationIdManager::mapStringToId(char const *variableName, int &id) +{ + DEBUG_FATAL(!s_installed, ("CustomizationIdManager not installed.")); + + //-- Lookup variable name in map. + TemporaryCrcString const crcVariableName(variableName, true); + StringIntMap::iterator const findIt = s_variableNameToId.find((const CrcString*)&crcVariableName); + + if (findIt == s_variableNameToId.end()) + { + // Not found. + return false; + } + else + { + // Found it. + id = findIt->second; + return true; + } +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.h new file mode 100644 index 00000000..bb73a464 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationIdManager.h @@ -0,0 +1,28 @@ +// ====================================================================== +// +// CustomizationIdManager.h +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationIdManager_H +#define INCLUDED_CustomizationIdManager_H + +// ====================================================================== + +class CustomizationIdManager +{ +public: + + static void install(char const *dataFilename); + + static bool mapIdToString(int id, std::string &variableName); + static bool mapIdToString(int id, char *variableName, int bufferLength); + + static bool mapStringToId(char const *variableName, int &id); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.cpp b/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.cpp new file mode 100644 index 00000000..15ed4dd6 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.cpp @@ -0,0 +1,49 @@ +// ====================================================================== +// +// CustomizationVariable.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationVariable.h" + +#include "sharedObject/CustomizationData.h" + +// ====================================================================== + +CustomizationVariable::~CustomizationVariable() +{ + m_owner = 0; +} + +// ====================================================================== + +CustomizationVariable::CustomizationVariable() : + m_owner(0) +{ +} + +// ---------------------------------------------------------------------- + +void CustomizationVariable::signalVariableModified() const +{ + if (m_owner) + { + // tell the owner one of its variables has been modified. + m_owner->signalModified(); + } +} + +// ---------------------------------------------------------------------- + +void CustomizationVariable::alter(CustomizationData & /* owner */) +{ + // Default does nothing. Very few of these need to handle alter. + // Alter is not called every frame --- on client it is only called after + // processing container changes, and then it only does something for + // the SlotRuleCustomizationVariable. +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.h b/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.h new file mode 100644 index 00000000..15d72b18 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/CustomizationVariable.h @@ -0,0 +1,106 @@ +// ====================================================================== +// +// CustomizationVariable.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationVariable_H +#define INCLUDED_CustomizationVariable_H + +// ====================================================================== + +class CustomizationVariable; +class ObjectTemplateCustomizationDataWriter; + +// ====================================================================== + +class CustomizationVariable +{ +friend class CustomizationData; + +public: + + typedef stdvector::fwd ByteVector; + +public: + + virtual ~CustomizationVariable(); + + virtual bool doesVariablePersist() const = 0; + virtual int getPersistedDataByteCount() const = 0; + + /** + * Append state of this variable to data buffer for subsequent restoration. + * + * @param data a vector of bytes where the state of this variable will be stored. + */ + virtual void saveToByteVector(ByteVector &data) const = 0; + + /** + * Restore the state of the variable using the data and offset provided. + * + * @param data a vector of bytes where the state of this variable was previously stored. + * @param startIndex a 0-based index into the data buffer indicating where this variable's state data begins. + * @param length length of the data recorded for this variable. + * + * @return true if data restoration occurred successfully; false if some error occured. + */ + virtual bool restoreFromByteVector(ByteVector const &data, int startIndex, int length) = 0; + + const CustomizationData *getOwner() const; + CustomizationData* getOwner(); + + virtual void writeObjectTemplateExportString(const std::string &variablePathName, ObjectTemplateCustomizationDataWriter &writer) const = 0; + +#ifdef _DEBUG + virtual std::string debugToString() const = 0; +#endif + + virtual void alter(CustomizationData &owner); + +protected: + + CustomizationVariable(); + + void signalVariableModified() const; + +private: + + void setOwner(CustomizationData *owner); + + // disabled + CustomizationVariable(const CustomizationVariable&); + CustomizationVariable &operator =(const CustomizationVariable&); + +private: + + CustomizationData *m_owner; + +}; + +// ====================================================================== + +inline const CustomizationData *CustomizationVariable::getOwner() const +{ + return m_owner; +} + +// ====================================================================== + +inline CustomizationData *CustomizationVariable::getOwner() +{ + return m_owner; +} + +// ====================================================================== + +inline void CustomizationVariable::setOwner(CustomizationData *owner) +{ + m_owner = owner; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.cpp b/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.cpp new file mode 100644 index 00000000..a02bf9d0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.cpp @@ -0,0 +1,228 @@ +// ====================================================================== +// +// ObjectTemplateCustomizationDataWriter.cpp +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectTemplateCustomizationDataWriter.h" + +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedMath/PaletteArgb.h" +#include "sharedMath/PaletteArgbList.h" + +#include +#include +#include + +// ====================================================================== + +ObjectTemplateCustomizationDataWriter::ObjectTemplateCustomizationDataWriter(bool writeSharedOwnerVariables) : + m_rangedIntData(new StringList()), + m_paletteColorData(new StringList()), + m_writeSharedOwnerVariables(writeSharedOwnerVariables) +{ +} + +// ---------------------------------------------------------------------- + +ObjectTemplateCustomizationDataWriter::~ObjectTemplateCustomizationDataWriter() +{ + delete m_paletteColorData; + delete m_rangedIntData; +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateCustomizationDataWriter::addRangedIntCustomizationVariable(const std::string &variableName, int minValueInclusive, int defaultValue, int maxValueExclusive) +{ + //-- Check for skipping shared_owner variables. + if (!m_writeSharedOwnerVariables) + { + bool const isSharedOwnerVariable = (static_cast(variableName.find("shared_owner")) != static_cast(std::string::npos)); + if (isSharedOwnerVariable) + { + // Skip it. + return; + } + } + + //-- Check for special case variable for breasts. + if (static_cast(variableName.find("blend_flat_chest")) != static_cast(std::string::npos)) + { + // Found this one, adjust minimum value. + minValueInclusive = -155; + maxValueExclusive = 156; + } + + //-- Write it out. + char conversionBuffer[64]; + + std::string buildString = "[variableName=\""; + buildString += variableName; + + buildString += "\", minValueInclusive="; + sprintf(conversionBuffer, "%d", minValueInclusive); + buildString += conversionBuffer; + + buildString += ", defaultValue="; + sprintf(conversionBuffer, "%d", defaultValue); + buildString += conversionBuffer; + + buildString += ", maxValueExclusive="; + sprintf(conversionBuffer, "%d", maxValueExclusive); + buildString += conversionBuffer; + + buildString += "],"; + + m_rangedIntData->push_back(buildString); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateCustomizationDataWriter::addPaletteColorCustomizationVariable(const std::string &variableName, const std::string &paletteReferenceName, int defaultPaletteIndex) +{ + //-- Check for skipping shared_owner variables. + if (!m_writeSharedOwnerVariables) + { + bool const isSharedOwnerVariable = (static_cast(variableName.find("shared_owner")) != static_cast(std::string::npos)); + if (isSharedOwnerVariable) + { + // Skip it. + return; + } + } + + //-- Fetch the palette, get the maxValueExclusive for it. + PaletteArgb const *const palette = PaletteArgbList::fetch(TemporaryCrcString(paletteReferenceName.c_str(), true)); + if (!palette) + { + FATAL(true, ("variable [%s] references non-existent palette [%s], variable will not be reported.", variableName.c_str(), paletteReferenceName.c_str())); + return; //lint !e527 // unreachable // Right, this is for MSDEV. + } + + int const paletteMaxValueExclusive = palette->getEntryCount(); + palette->release(); + + //-- Build export string. + char conversionBuffer[64]; + + std::string buildString = "[variableName=\""; + buildString += variableName; + + buildString += "\", palettePathName=\""; + buildString += paletteReferenceName; + + buildString += "\", defaultPaletteIndex="; + sprintf(conversionBuffer, "%d", defaultPaletteIndex); + buildString += conversionBuffer; + buildString += "], // maxValueExclusive="; + + sprintf(conversionBuffer, "%d", paletteMaxValueExclusive); + buildString += conversionBuffer; + + m_paletteColorData->push_back(buildString); +} + +// ---------------------------------------------------------------------- + +bool ObjectTemplateCustomizationDataWriter::writeToFile(const std::string &pathName, bool allowOverwrite) +{ + //-- Don't write anything if there's no data to write. + bool hasData = false; + + if (!m_paletteColorData->empty()) + hasData = true; + + if (!m_rangedIntData->empty()) + hasData = true; + + if (!hasData) + { + DEBUG_REPORT_LOG(true, ("writeToFile(): no data: skipped writing [%s].\n", pathName.c_str())); + return true; + } + + //-- Handle no-overwrite case. + if (!allowOverwrite) + { + FILE *const testFile = fopen(pathName.c_str(), "r"); + if (testFile != NULL) + { + fclose(testFile); + DEBUG_REPORT_LOG(true, ("writeToFile(): overwrite attempt: skipped writing [%s] because it already exists and allowOverwrite == false.\n", pathName.c_str())); + return false; + } + } + + //-- open file + FILE *const file = fopen(pathName.c_str(), "w"); + if (!file) + { + WARNING(true, ("failed to create file [%s].", pathName.c_str())); + return false; + } + + //-- sort the output data + m_paletteColorData->sort(); + m_rangedIntData->sort(); + + //-- write palette color variables + fprintf(file, "paletteColorCustomizationVariables = ["); + { + int i = 0; + int const count = static_cast(m_paletteColorData->size()); + + const StringList::iterator endIt = m_paletteColorData->end(); + for (StringList::iterator it = m_paletteColorData->begin(); it != endIt; ++it, ++i) + { + if (i == (count - 1)) + { + // -- Fixup last entry to use ] in place of final comma. + std::string::size_type position = it->rfind(','); + DEBUG_FATAL(static_cast(position) == static_cast(std::string::npos), ("bad data, where's the final comma?")); + + (*it)[position] = ']'; + } + + fprintf(file, "\n %s", it->c_str()); + } + } + if (m_paletteColorData->empty()) + fprintf(file, "]"); + fprintf(file, "\n\n"); + + //-- write ranged int variables + fprintf(file, "rangedIntCustomizationVariables = ["); + { + int i = 0; + int const count = static_cast(m_rangedIntData->size()); + + const StringList::iterator endIt = m_rangedIntData->end(); + for (StringList::iterator it = m_rangedIntData->begin(); it != endIt; ++it, ++i) + { + if (i == (count - 1)) + { + // -- Fixup last entry to use ] in place of final comma. + std::string::size_type position = it->rfind(','); + DEBUG_FATAL(static_cast(position) == static_cast(std::string::npos), ("bad data, where's the final comma?")); + + (*it)[position] = ']'; + } + + fprintf(file, "\n %s", it->c_str()); + } + } + if (m_rangedIntData->empty()) + fprintf(file, "]"); + fprintf(file, "\n\n"); + + fclose(file); + + //-- return success + return true; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.h b/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.h new file mode 100644 index 00000000..1724a1b3 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/ObjectTemplateCustomizationDataWriter.h @@ -0,0 +1,58 @@ +// ====================================================================== +// +// ObjectTemplateCustomizationDataWriter.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ObjectTemplateCustomizationDataWriter_H +#define INCLUDED_ObjectTemplateCustomizationDataWriter_H + +// ====================================================================== + +// -TRF- replace this with whatever flag is needed to include for internal-only +// builds. For now it is DEBUG-enabled only. + +#ifdef _DEBUG +#define USE_OBJ_TEMPLATE_CUSTOM_VAR_WRITER 1 +#else +#define USE_OBJ_TEMPLATE_CUSTOM_VAR_WRITER 0 +#endif + +// ====================================================================== + +class ObjectTemplateCustomizationDataWriter +{ +public: + + ObjectTemplateCustomizationDataWriter(bool writeSharedOwnerVariables); + ~ObjectTemplateCustomizationDataWriter(); + + void addRangedIntCustomizationVariable(const std::string &variableName, int minValueInclusive, int defaultValue, int maxValueExclusive); + void addPaletteColorCustomizationVariable(const std::string &variableName, const std::string &paletteReferenceName, int defaultPaletteIndex); + + bool writeToFile(const std::string &pathName, bool allowOverwrite); + +private: + + typedef stdlist::fwd StringList; + +private: + + // Disabled. + ObjectTemplateCustomizationDataWriter(const ObjectTemplateCustomizationDataWriter&); + ObjectTemplateCustomizationDataWriter &operator =(const ObjectTemplateCustomizationDataWriter&); + +private: + + StringList *m_rangedIntData; + StringList *m_paletteColorData; + + bool m_writeSharedOwnerVariables; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.cpp b/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.cpp new file mode 100644 index 00000000..d83e99a3 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.cpp @@ -0,0 +1,146 @@ +// ====================================================================== +// +// PaletteColorCustomizationVariable.cpp +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/PaletteColorCustomizationVariable.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedMath/PackedArgb.h" +#include "sharedMath/PaletteArgb.h" +#include "sharedObject/ObjectTemplateCustomizationDataWriter.h" + +#include +#include + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(PaletteColorCustomizationVariable, true, 0, 0, 0); + +// ====================================================================== + +PaletteColorCustomizationVariable::PaletteColorCustomizationVariable(const PaletteArgb *palette, int selectedIndex) +: RangedIntCustomizationVariable(), + m_palette(palette), + m_paletteIndex(selectedIndex) +{ + NOT_NULL(palette); + palette->fetch(); + + int const paletteEntryCount = m_palette->getEntryCount(); + if ((m_paletteIndex < 0) || (m_paletteIndex >= paletteEntryCount)) + { + DEBUG_WARNING(true, ("Initializing palette var for palette=[%s] with out-of-range value [%d], valid range is [0..%d], defaulting to [%d].", m_palette->getName().getString(), m_paletteIndex, paletteEntryCount - 1, paletteEntryCount - 1)); + m_paletteIndex = paletteEntryCount - 1; + } +} + +// ---------------------------------------------------------------------- + +PaletteColorCustomizationVariable::~PaletteColorCustomizationVariable() +{ + //lint -esym(1540, PaletteColorCustomizationVariable::m_palette) // not freed or zero'ed // yes, but released + m_palette->release(); +} + +// ---------------------------------------------------------------------- + +int PaletteColorCustomizationVariable::getValue() const +{ + return m_paletteIndex; +} + +// ---------------------------------------------------------------------- + +bool PaletteColorCustomizationVariable::setValue(int value) +{ + if ((value >= 0) && (value < m_palette->getEntryCount())) + { + // change the value + m_paletteIndex = value; + + // notify owner CustomizationData about change. + signalVariableModified(); + } + else + { + DEBUG_WARNING(true, ("attempted to set PaletteColorCustomizationVariable to %d, outside valid range [%d,%d).", value, 0, m_palette->getEntryCount())); + return false; + } + + return RangedIntCustomizationVariable::setValue(value); +} + +// ---------------------------------------------------------------------- + +const PackedArgb &PaletteColorCustomizationVariable::getValueAsColor() const +{ + if (!m_palette) + return PackedArgb::solidMagenta; + + int const usePaletteIndex = clamp(0, m_paletteIndex, m_palette->getEntryCount() - 1); + bool error = false; + PackedArgb const & color = m_palette->getEntry(usePaletteIndex, error); + + WARNING(error, ("PaletteColorCustomizationVariable::getValueAsColor error")); + return color; +} + +// ---------------------------------------------------------------------- + +void PaletteColorCustomizationVariable::getRange(int &minRangeInclusive, int &maxRangeExclusive) const +{ + minRangeInclusive = 0; + maxRangeExclusive = m_palette->getEntryCount(); +} + +// ---------------------------------------------------------------------- + +const PaletteArgb *PaletteColorCustomizationVariable::fetchPalette() const +{ + m_palette->fetch(); + return m_palette; +} + +// ---------------------------------------------------------------------- + +void PaletteColorCustomizationVariable::setClosestColor(const PackedArgb &targetColor) +{ + setValue(m_palette->findClosestMatch(targetColor)); +} + +// ---------------------------------------------------------------------- + +void PaletteColorCustomizationVariable::writeObjectTemplateExportString(const std::string &variablePathName, ObjectTemplateCustomizationDataWriter &writer) const +{ +#if !(USE_OBJ_TEMPLATE_CUSTOM_VAR_WRITER) + UNREF(variablePathName); + UNREF(writer); +#else + //-- this assumes that the current value is the default value --- if the user changed values at all, they + // will not be the artist's built in default. + writer.addPaletteColorCustomizationVariable(variablePathName, m_palette->getName().getString(), m_paletteIndex); +#endif +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +std::string PaletteColorCustomizationVariable::debugToString() const +{ + char buffer[1024]; + + sprintf(buffer, "palette (%s): index %d", m_palette->getName().getString(), m_paletteIndex); + return std::string(buffer); + +} + +#endif + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.h b/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.h new file mode 100644 index 00000000..1008620a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/PaletteColorCustomizationVariable.h @@ -0,0 +1,64 @@ +// ====================================================================== +// +// PaletteColorCustomizationVariable.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PaletteColorCustomizationVariable_H +#define INCLUDED_PaletteColorCustomizationVariable_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/RangedIntCustomizationVariable.h" + +class MemoryBlockManager; +class PackedArgb; +class PaletteArgb; + +// ====================================================================== + +class PaletteColorCustomizationVariable: public RangedIntCustomizationVariable +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + PaletteColorCustomizationVariable(const PaletteArgb *palette, int selectedIndex = 0); + virtual ~PaletteColorCustomizationVariable(); + + virtual int getValue() const; + virtual bool setValue(int value); + const PackedArgb &getValueAsColor() const; + + virtual void getRange(int &minRangeInclusive, int &maxRangeExclusive) const; + + virtual void writeObjectTemplateExportString(const std::string &variablePathName, ObjectTemplateCustomizationDataWriter &writer) const; + + const PaletteArgb *fetchPalette() const; + + void setClosestColor(const PackedArgb &targetColor); + +#ifdef _DEBUG + virtual std::string debugToString() const; +#endif + +private: + + // disabled + PaletteColorCustomizationVariable(); + PaletteColorCustomizationVariable(const PaletteColorCustomizationVariable&); + PaletteColorCustomizationVariable &operator =(const PaletteColorCustomizationVariable&); + +private: + + const PaletteArgb *const m_palette; + int m_paletteIndex; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.cpp b/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.cpp new file mode 100644 index 00000000..30a87733 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.cpp @@ -0,0 +1,285 @@ +// ====================================================================== +// +// RangedIntCustomizationVariable.cpp +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/RangedIntCustomizationVariable.h" +#include "sharedObject/CustomizationData.h" + +#include +#include +#include +#include + +// ====================================================================== + +bool RangedIntCustomizationVariable::doesVariablePersist() const +{ + // all ranged ints are meant to persist + return true; +} + +// ---------------------------------------------------------------------- + +int RangedIntCustomizationVariable::getPersistedDataByteCount() const +{ + //-- Get the range. + int minInclusive = 0; + int maxExclusive = 0; + + getRange(minInclusive, maxExclusive); + + if ((minInclusive >= 0) && (minInclusive < 255) && (maxExclusive > 0) && (maxExclusive <= 256)) + { + // Value fits in a single unsigned byte. + return 1; + } + else + { + //-- If either of these get hit, we've got to upgrade the customization data format. + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(std::numeric_limits::min(), static_cast(minInclusive), std::numeric_limits::max()); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(static_cast(std::numeric_limits::min()), maxExclusive, static_cast(std::numeric_limits::max()) + 1); + + // Value fits in a signed 16-bit int. + return 2; + } +} + +// ---------------------------------------------------------------------- + +#if 0 + +std::string RangedIntCustomizationVariable::writeToString() const +{ + char buffer[64]; + sprintf(buffer, "%x", getValue()); + return std::string(buffer); +} + +#endif + +// ---------------------------------------------------------------------- + +#if 0 + +bool RangedIntCustomizationVariable::loadFromString(int version, const std::string &data) +{ + if (version == 2) + return loadFromString_0002(data); + else + { + WARNING(true, ("loadFromString(): version %d unsupported.\n", version)); + return false; + } +} + +#endif + +// ---------------------------------------------------------------------- + +void RangedIntCustomizationVariable::saveToByteVector(ByteVector &data) const +{ + int const byteCount = getPersistedDataByteCount(); + switch (byteCount) + { + case 1: + { + // Store as single unsigned byte. + byte const value = static_cast(getValue()); + data.push_back(value); + break; + } + + case 2: + { + // Treated as little-endian signed 16-bit number (least significant byte earliest/first in memory). + int16 const value = static_cast(getValue()); + + byte const lowerByte = static_cast(static_cast(value) & 0x00ff); + data.push_back(lowerByte); + + byte const upperByte = static_cast((static_cast(value) >> 8) & 0x00ff); + data.push_back(upperByte); + break; + } + + default: + FATAL(true, ("saveToByteVector(): failed, unsupported byte count [%d] specified, should be 1 or 2.", byteCount)); + } +} + +// ---------------------------------------------------------------------- + +bool RangedIntCustomizationVariable::restoreFromByteVector(ByteVector const &data, int startIndex, int length) +{ + if (startIndex < 0) + { + WARNING(true, ("restoreFromByteVector(): invalid startIndex [%d]", startIndex)); + return false; + } + + switch (length) + { + case 1: + { + //-- Handle unsigned byte packing. + + // Check range. + if (startIndex >= static_cast(data.size())) + { + WARNING(true, ("restoreFromByteVector(): attempting to restore unsigned byte int but not enough data.")); + return false; + } + + // Restore as single unsigned byte. + setValue(static_cast(data[static_cast(startIndex)])); + break; + } + + case 2: + { + //-- Handle signed int packing. + // Check range. + if (startIndex + 1 >= static_cast(data.size())) + { + WARNING(true, ("restoreFromByteVector(): attempting to restore short signed int but not enough data.")); + return false; + } + + // Restore as single unsigned byte. + uint32 const lowByte = static_cast(data[static_cast(startIndex)]); + uint32 const hiByte = static_cast(data[static_cast(startIndex + 1)]); + + int16 const value = static_cast((hiByte << 8) | lowByte); + setValue(value); + break; + } + + default: + FATAL(true, ("saveToByteVector(): failed, unsupported length [%d] specified, should be 1 or 2.", length)); + } + + // Success. + return true; +} + +// ====================================================================== + +RangedIntCustomizationVariable::RangedIntCustomizationVariable() +: CustomizationVariable(), + m_dependentVariable(0), + m_isDependentVariable(false) +{ +} + +// ====================================================================== + +#if 0 + +bool RangedIntCustomizationVariable::loadFromString_0002(const std::string &data) +{ + int newValue; + + const int scanfResult = sscanf(data.c_str(), "%x", &newValue); + if (scanfResult != 1) + { + // failed + return false; + } + else + { + setValue(newValue); + return true; + } +} + +#endif + +//---------------------------------------------------------------------- + +/** +* This function computes the normalized value. +* @return a number in [0.0,1.0] +*/ + +float RangedIntCustomizationVariable::getNormalizedFloatValue() const +{ + int low = 0, high = 0; + getRange (low, high); + const float range = static_cast(high - low); + if (range <= 0.0f) + return 0.0f; + + return clamp (0.0f, static_cast(getValue () - low) / range, 1.0f); +} + +//---------------------------------------------------------------------- + +/** +* This function sets the normalized value +* @param value a number in [0.0,1.0] +*/ + +void RangedIntCustomizationVariable::setNormalizedFloatValue(float value) +{ + int low = 0, high = 0; + getRange (low, high); + const float range = static_cast(high - low); + setValue (std::min (low + static_cast(value * range), (high - 1))); +} + +//---------------------------------------------------------------------- + +int RangedIntCustomizationVariable::getRangeSize() const +{ + int low = 0; + int high = 0; + getRange (low, high); + + return high - low; +} + +// ====================================================================== +void RangedIntCustomizationVariable::setDependentVariable(const std::string &variablePathName) +{ + if(getOwner()) + { + RangedIntCustomizationVariable * const var = safe_cast(getOwner()->findVariable(variablePathName)); + if(var) + { + m_dependentVariable = var; + var->setIsDependentVariable(true); + } + } +} + +// ====================================================================== +void RangedIntCustomizationVariable::setIsDependentVariable(bool const isDependentVariable) +{ + m_isDependentVariable = isDependentVariable; +} + +// ====================================================================== +bool RangedIntCustomizationVariable::getIsDependentVariable() const +{ + return m_isDependentVariable; +} + +// ====================================================================== + +bool RangedIntCustomizationVariable::setValue(int value) +{ + if(m_dependentVariable) + { + if (!m_dependentVariable->setValue(value)) + return false; + } + + return true; +} + +//---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.h b/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.h new file mode 100644 index 00000000..8c172383 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/customization/RangedIntCustomizationVariable.h @@ -0,0 +1,63 @@ +// ====================================================================== +// +// RangedIntCustomizationVariable.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_RangedIntCustomizationVariable_H +#define INCLUDED_RangedIntCustomizationVariable_H + +// ====================================================================== + +#include "sharedObject/CustomizationVariable.h" + +// ====================================================================== + +class RangedIntCustomizationVariable: public CustomizationVariable +{ +public: + + virtual bool doesVariablePersist() const; + virtual int getPersistedDataByteCount() const; + + virtual void saveToByteVector(ByteVector &data) const; + virtual bool restoreFromByteVector(ByteVector const &data, int startIndex, int length); + + virtual int getValue() const = 0; + virtual bool setValue(int value); + + virtual void getRange(int &minRangeInclusive, int &maxRangeExclusive) const = 0; + + float getNormalizedFloatValue() const; + void setNormalizedFloatValue(float value); + + int getRangeSize() const; + + void setDependentVariable(const std::string &variablePathName); + void setIsDependentVariable(bool isDependentVariable); + bool getIsDependentVariable() const; + + +protected: + + RangedIntCustomizationVariable(); + +private: + +#if 0 + bool loadFromString_0002(const std::string &data); +#endif + + // disabled + RangedIntCustomizationVariable(const RangedIntCustomizationVariable&); + RangedIntCustomizationVariable &operator =(const RangedIntCustomizationVariable&); + + RangedIntCustomizationVariable *m_dependentVariable; + bool m_isDependentVariable; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.cpp new file mode 100644 index 00000000..16b2d067 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.cpp @@ -0,0 +1,56 @@ +// ====================================================================== +// +// Dynamics.cpp +// copyright 1999, bootprint entertainment +// copyright 2002, sony online entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Dynamics.h" + +#include "sharedObject/AlterResult.h" + +// ====================================================================== +// Construct a new dynamics +// +// Remarks: +// +// This routine does nothing, but is provided for interface reasons for +// this base class. + +Dynamics::Dynamics (Object* const owner) : + m_owner (owner) +{ +} + +// ---------------------------------------------------------------------- +/** + * Destroy a new dynamics. + * + * This routine does nothing, but is provided for interface reasons for + * this base class. + */ + +Dynamics::~Dynamics () +{ + m_owner = 0; +} + +// ---------------------------------------------------------------------- +/** + * Alter a dynamics. + * + * This routine does nothing, but is provided for interface reasons for + * this base class. + * + * @param time The amount of time elapse since the last alter + */ + +float Dynamics::alter (float /*time*/) +{ + // Indicate there's no reason to alter based on functionality in this class. + return AlterResult::cms_keepNoAlter; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.h new file mode 100644 index 00000000..c558421f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/Dynamics.h @@ -0,0 +1,69 @@ +// ====================================================================== +// +// Dynamics.h +// copyright 1999, bootprint entertainment +// copyright 2002, sony online entertainment +// +// derived classes from dynamics should be using dynamics templates +// +// ====================================================================== + +#ifndef INCLUDED_Dynamics_H +#define INCLUDED_Dynamics_H + +// ====================================================================== + +class Object; + +// ====================================================================== +// Abstract dynamics entity for an object + +class Dynamics +{ +public: + + explicit Dynamics (Object* newOwner); + virtual ~Dynamics () = 0; + + virtual float alter(float time); + + void setOwner (Object* newOwner); + const Object* getOwner () const; + Object* getOwner (); + +private: + + // disable these + Dynamics (); + Dynamics (const Dynamics&); + Dynamics& operator= (const Dynamics&); + +private: + + Object* m_owner; +}; + +// ====================================================================== + +inline void Dynamics::setOwner (Object* const owner) +{ + m_owner = owner; +} + +// ---------------------------------------------------------------------- + +inline const Object* Dynamics::getOwner () const +{ + return m_owner; +} + +// ---------------------------------------------------------------------- + +inline Object* Dynamics::getOwner () +{ + return m_owner; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.cpp new file mode 100644 index 00000000..f21f2532 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.cpp @@ -0,0 +1,61 @@ +// ====================================================================== +// +// PulseDynamics.cpp +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/PulseDynamics.h" + +#include "sharedMath/Vector.h" +#include "sharedObject/Object.h" + +//====================================================================== + +PulseDynamics::PulseDynamics(Object *owner, float minimumSize, float maximumSize, float speed) +: SimpleDynamics(owner) +, m_minimumSize(minimumSize) +, m_maximumSize(maximumSize) +, m_speed(speed) +, m_baseScale(owner->getScale()) +, m_currentSize(1.0f) +, m_pulseGrowDirection(1.0f) +{ +} + +// ---------------------------------------------------------------------- + +PulseDynamics::~PulseDynamics() +{ + Object *const ownerObject = getOwner(); + if (ownerObject != 0) + { + ownerObject->setRecursiveScale(m_baseScale); + } +} + +// ---------------------------------------------------------------------- + +float PulseDynamics::alter(float elapsedTime) +{ + Object *const ownerObject = getOwner(); + if (ownerObject != 0) + { + m_currentSize += (elapsedTime * m_speed * m_pulseGrowDirection); + + if (!WithinRangeInclusiveInclusive(m_minimumSize, m_currentSize, m_maximumSize)) + { + m_currentSize = clamp(m_minimumSize, m_currentSize, m_maximumSize); + m_pulseGrowDirection *= -1.0f; + } + + Vector scale = m_baseScale * m_currentSize; + ownerObject->setRecursiveScale(scale); + } + + return SimpleDynamics::alter(elapsedTime); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.h new file mode 100644 index 00000000..c36bec49 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/PulseDynamics.h @@ -0,0 +1,42 @@ +// ====================================================================== +// +// PulseDynamics.h +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PulseDynamics_H +#define INCLUDED_PulseDynamics_H + +// ====================================================================== + +#include "sharedObject/SimpleDynamics.h" + +// ====================================================================== + +class PulseDynamics: public SimpleDynamics +{ +public: + PulseDynamics(Object *owner, float minimumSize, float maximumSize, float speed = 1.0f); + virtual ~PulseDynamics(); + virtual float alter(float elapsedTime); + +private: + PulseDynamics(); + PulseDynamics(const PulseDynamics &); + PulseDynamics &operator =(const PulseDynamics &); + +private: + float m_minimumSize; + float m_maximumSize; + float m_speed; + + Vector m_baseScale; + float m_currentSize; + float m_pulseGrowDirection; // this should only ever by 1.0f or -1.0f +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.cpp new file mode 100644 index 00000000..aabfc460 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.cpp @@ -0,0 +1,71 @@ +//=================================================================== +// +// RotationDynamics.cpp +// asommers 6-19-99 +// +// copyright 1999, bootprint entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/RotationDynamics.h" + +#include "sharedObject/Object.h" +#include "sharedRandom/Random.h" + +//=================================================================== +// PUBLIC RotationDynamics +//=================================================================== + +RotationDynamics::RotationDynamics (Object* const owner, const Vector& rotationsPerSecond) : + StateDynamics (owner), + m_rotationsPerSecond (rotationsPerSecond), + m_rotateAroundAppearanceCenter(false) +{ +} + +//------------------------------------------------------------------- + +RotationDynamics::~RotationDynamics () +{ +} + +//---------------------------------------------------------------------- + +void RotationDynamics::setRotateAroundAppearanceCenter(bool rotateAroundAppearanceCenter) +{ + m_rotateAroundAppearanceCenter = rotateAroundAppearanceCenter; +} + +//=================================================================== +// PROTECTED RotationDynamics +//=================================================================== + +void RotationDynamics::realAlter (const float elapsedTime) +{ + StateDynamics::realAlter (elapsedTime); + + Object* const owner = getOwner (); + if (!owner) + return; + + if (m_rotateAroundAppearanceCenter) + { + Transform t = owner->getTransform_o2p(); + t.move_l(owner->getAppearanceSphereCenter()); + t.yaw_l(m_rotationsPerSecond.x * elapsedTime); + t.pitch_l(m_rotationsPerSecond.y * elapsedTime); + t.roll_l(m_rotationsPerSecond.z * elapsedTime); + t.move_l(-owner->getAppearanceSphereCenter()); + + owner->setTransform_o2p(t); + } + else + { + owner->yaw_o (m_rotationsPerSecond.x * elapsedTime); + owner->pitch_o (m_rotationsPerSecond.y * elapsedTime); + owner->roll_o (m_rotationsPerSecond.z * elapsedTime); + } +} + +//=================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.h new file mode 100644 index 00000000..32aa7c99 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/RotationDynamics.h @@ -0,0 +1,47 @@ +//=================================================================== +// +// RotationDynamics.h +// asommers 12-12-2000 +// +// a simple dynamics class showing how to use it +// +//=================================================================== + +#ifndef INCLUDED_RotationDynamics_H +#define INCLUDED_RotationDynamics_H + +//=================================================================== + +#include "sharedMath/Vector.h" +#include "sharedObject/StateDynamics.h" + +//=================================================================== + +class RotationDynamics : public StateDynamics +{ +public: + + RotationDynamics (Object* owner, const Vector& rotationsPerSecond); + virtual ~RotationDynamics (); + + void setRotateAroundAppearanceCenter(bool rotateAroundAppearanceCenter); + +protected: + + virtual void realAlter (float elapsedTime); + +private: + + RotationDynamics (); + RotationDynamics (const RotationDynamics&); + RotationDynamics& operator= (const RotationDynamics&); + +private: + + const Vector m_rotationsPerSecond; + bool m_rotateAroundAppearanceCenter; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.cpp new file mode 100644 index 00000000..82d0bf00 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.cpp @@ -0,0 +1,61 @@ +//=================================================================== +// +// SeesawDynamics.cpp +// asommers 6-19-99 +// +// copyright 1999, bootprint entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SeesawDynamics.h" + +#include "sharedObject/Object.h" +#include "sharedRandom/Random.h" + +//=================================================================== +// PUBLIC SeesawDynamics +//=================================================================== + +SeesawDynamics::SeesawDynamics (Object* const owner, const Type type, const float seesawsPerSecond, const float seesawMagnitude) : + StateDynamics (owner), + m_type (type), + m_seesawsPerSecond (seesawsPerSecond), + m_seesawMagnitude (seesawMagnitude), + m_dy (Random::randomReal (0.0f, PI_TIMES_2)) +{ +} + +//------------------------------------------------------------------- + +SeesawDynamics::~SeesawDynamics () +{ +} + +//------------------------------------------------------------------- + +void SeesawDynamics::realAlter (const float elapsedTime) +{ + StateDynamics::realAlter (elapsedTime); + + Object* const owner = getOwner (); + if (!owner) + return; + + //-- rotation + m_dy += elapsedTime; + + const float t = (sin (m_seesawsPerSecond * m_dy) + 1.f) * 0.5f; + const float angle = linearInterpolate (-m_seesawMagnitude, m_seesawMagnitude, t); + + owner->resetRotate_o2p (); + + switch (m_type) + { + case T_yaw: owner->yaw_o (angle); break; + case T_pitch: owner->pitch_o (angle); break; + case T_roll: owner->roll_o (angle); break; + } +} + +//=================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.h new file mode 100644 index 00000000..17139d19 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SeesawDynamics.h @@ -0,0 +1,56 @@ +//=================================================================== +// +// SeesawDynamics.h +// asommers 12-12-2000 +// +// a simple dynamics class showing how to use it +// +//=================================================================== + +#ifndef INCLUDED_SeesawDynamics_H +#define INCLUDED_SeesawDynamics_H + +//=================================================================== + +#include "sharedObject/StateDynamics.h" + +//=================================================================== + +class SeesawDynamics : public StateDynamics +{ +public: + + enum Type + { + T_yaw, + T_pitch, + T_roll + }; + +public: + + SeesawDynamics (Object* owner, Type type, float seesawsPerSecond, float seesawMagnitude); + virtual ~SeesawDynamics (); + +protected: + + virtual void realAlter (float elapsedTime); + +private: + + SeesawDynamics (); + SeesawDynamics (const SeesawDynamics&); + SeesawDynamics& operator= (const SeesawDynamics&); + +private: + + const Type m_type; + const float m_seesawsPerSecond; + const float m_seesawMagnitude; + + float m_dy; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.cpp new file mode 100644 index 00000000..19dcf9f8 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.cpp @@ -0,0 +1,110 @@ +//=================================================================== +// +// SimpleDynamics.cpp +// copyright 1999, bootprint entertainment +// copyright 2002, sony online entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SimpleDynamics.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/Object.h" + +//=================================================================== + +SimpleDynamics::SimpleDynamics (Object* const owner) : + Dynamics (owner), + m_currentVelocity (), + m_movementSpace (WorldSpace) +{ +} + +//------------------------------------------------------------------- + +SimpleDynamics::~SimpleDynamics () +{ +} + +//------------------------------------------------------------------- + +Vector const &SimpleDynamics::getCurrentVelocity_w() const +{ + FATAL(m_movementSpace != WorldSpace && m_currentVelocity != Vector::zero, ("SimpleDynamics::getCurrentVelocity_w called when velocity is not in world space")); + return m_currentVelocity; +} + +//------------------------------------------------------------------- + +void SimpleDynamics::setCurrentVelocity_w(Vector const &newCurrentVelocity_w) +{ + m_movementSpace = WorldSpace; + m_currentVelocity = newCurrentVelocity_w; +} + +//------------------------------------------------------------------- + +Vector const &SimpleDynamics::getCurrentVelocity_p() const +{ + FATAL(m_movementSpace != ParentSpace && m_currentVelocity != Vector::zero, ("SimpleDynamics::getCurrentVelocity_p called when velocity is not in parent space")); + return m_currentVelocity; +} + +//------------------------------------------------------------------- + +void SimpleDynamics::setCurrentVelocity_p(Vector const &newCurrentVelocity_p) +{ + m_movementSpace = ParentSpace; + m_currentVelocity = newCurrentVelocity_p; +} + +//------------------------------------------------------------------- + +Vector const &SimpleDynamics::getCurrentVelocity_o() const +{ + FATAL(m_movementSpace != ObjectSpace && m_currentVelocity != Vector::zero, ("SimpleDynamics::getCurrentVelocity_o called when velocity is not in object space")); + return m_currentVelocity; +} + +//------------------------------------------------------------------- + +void SimpleDynamics::setCurrentVelocity_o(Vector const &newCurrentVelocity_o) +{ + m_movementSpace = ObjectSpace; + m_currentVelocity = newCurrentVelocity_o; +} + +//------------------------------------------------------------------- + +float SimpleDynamics::alter (const float time) +{ + float const baseAlterResult = Dynamics::alter (time); + UNREF (baseAlterResult); + + if (getOwner () && m_currentVelocity != Vector::zero) + { + switch (m_movementSpace) + { + case WorldSpace: + getOwner ()->move_o (getOwner ()->rotate_w2o (m_currentVelocity * time)); + break; + case ParentSpace: + getOwner ()->move_o (getOwner ()->rotate_p2o (m_currentVelocity * time)); + break; + case ObjectSpace: + getOwner ()->move_o (m_currentVelocity * time); + break; + } + } + + // @todo if worthwhile, figure out a way to have an inactive SimpleDynamics + // return that it doesn't need an alter next frame. Then a mechanism + // will be needed to cause an AlterScheduler::submitForAlter() if + // something causes the dynamics to require an alter. + // + // For now, all simple dynamics get an alter every frame. + return AlterResult::cms_alterNextFrame; +} + +//=================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.h new file mode 100644 index 00000000..dd2c252f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SimpleDynamics.h @@ -0,0 +1,58 @@ +//=================================================================== +// +// SimpleDynamics.h +// copyright 1999, bootprint entertainment +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_SimpleDynamics_H +#define INCLUDED_SimpleDynamics_H + +//=================================================================== + +#include "sharedObject/Dynamics.h" +#include "sharedMath/Vector.h" + +//=================================================================== + +class SimpleDynamics : public Dynamics +{ +public: + + enum MovementSpace + { + WorldSpace, + ParentSpace, + ObjectSpace + }; + + explicit SimpleDynamics(Object *newOwner); + virtual ~SimpleDynamics(); + + virtual float alter(float time); + + Vector const &getCurrentVelocity_w() const; + void setCurrentVelocity_w(Vector const &newCurrentVelocity_w); + Vector const &getCurrentVelocity_p() const; + void setCurrentVelocity_p(Vector const &newCurrentVelocity_p); + Vector const &getCurrentVelocity_o() const; + void setCurrentVelocity_o(Vector const &newCurrentVelocity_o); + +private: + + SimpleDynamics(); + SimpleDynamics(SimpleDynamics const &); + SimpleDynamics &operator=(SimpleDynamics const &); + +private: + + Vector m_currentVelocity; + MovementSpace m_movementSpace; +}; + +//=================================================================== + +#endif + + diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.cpp new file mode 100644 index 00000000..109244cb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.cpp @@ -0,0 +1,69 @@ +//=================================================================== +// +// SpringDynamics.cpp +// asommers 6-19-99 +// +// copyright 1999, bootprint entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/SpringDynamics.h" + +#include "sharedObject/Object.h" +#include "sharedRandom/Random.h" + +//=================================================================== +// PUBLIC SpringDynamics +//=================================================================== + +SpringDynamics::SpringDynamics (Object* const owner, const Vector& offset, const Vector& springDirection, float springMagnitude, float springsPerSecond) : + StateDynamics (owner), + m_parent (0), + m_offset (offset), + m_springDirection (springDirection), + m_springMagnitude (springMagnitude), + m_springsPerSecond (springsPerSecond), + m_dy (Random::randomReal (0.0f, PI_TIMES_2)), + m_position () +{ +} + +//------------------------------------------------------------------- + +SpringDynamics::~SpringDynamics () +{ + // the parent object isn't owned by this instance + m_parent = 0; +} + +//------------------------------------------------------------------- + +void SpringDynamics::setPosition (const Vector& position) +{ + m_position = position; +} + +//=================================================================== +// PROTECTED SpringDynamics +//=================================================================== + +void SpringDynamics::realAlter (const float time) +{ + StateDynamics::realAlter (time); + + Object* const owner = getOwner (); + if (!owner) + return; + + if (m_springsPerSecond > 0.f) + { + m_dy += time; + + const Vector springDirection = owner->rotate_o2p (m_springDirection) * sin (m_springsPerSecond * m_dy * 8.0f) * m_springMagnitude; + owner->setPosition_p (m_position + m_offset + springDirection); + } +} + +//=================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.h new file mode 100644 index 00000000..09fc42ec --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/SpringDynamics.h @@ -0,0 +1,53 @@ +//=================================================================== +// +// SpringDynamics.h +// asommers 12-12-2000 +// +// a simple dynamics class showing how to use it +// +//=================================================================== + +#ifndef INCLUDED_SpringDynamics_H +#define INCLUDED_SpringDynamics_H + +//=================================================================== + +#include "sharedObject/StateDynamics.h" +#include "sharedMath/Vector.h" + +//=================================================================== + +class SpringDynamics : public StateDynamics +{ +public: + + SpringDynamics (Object* owner, const Vector& offset, const Vector& springDirection, float springMagnitude, float springsPerSecond); + virtual ~SpringDynamics (); + + void setPosition (const Vector& position); + +protected: + + virtual void realAlter (float time); + +private: + + SpringDynamics (); + SpringDynamics (const SpringDynamics&); + SpringDynamics& operator= (const SpringDynamics&); + +private: + + const Object* m_parent; + const Vector m_offset; + const Vector m_springDirection; + const float m_springMagnitude; + const float m_springsPerSecond; + + float m_dy; + Vector m_position; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.cpp new file mode 100644 index 00000000..15695cae --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.cpp @@ -0,0 +1,106 @@ +//=================================================================== +// +// StateDynamics.cpp +// asommers 6-19-99 +// +// copyright 1999, bootprint entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/StateDynamics.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/Object.h" +#include "sharedRandom/Random.h" + +//=================================================================== +// PUBLIC StateDynamics +//=================================================================== + +StateDynamics::StateDynamics (Object* const owner) : + Dynamics (owner), + m_state (S_off), + m_stateTimer (5.f) +{ +} + +//------------------------------------------------------------------- + +StateDynamics::~StateDynamics () +{ +} + +//------------------------------------------------------------------- + +float StateDynamics::alter (const float elapsedTime) +{ + float const baseAlterResult = Dynamics::alter (elapsedTime); + UNREF (baseAlterResult); + + Object* const owner = getOwner (); + if (!owner) + { + // @todo should we request a kill in this condition? + return AlterResult::cms_alterNextFrame; + } + + switch (m_state) + { + case S_off: + break; + + case S_offToOn: + { + if (m_stateTimer.updateZero (elapsedTime)) + { + m_state = S_on; + realAlter (elapsedTime); + } + else + realAlter (elapsedTime * m_stateTimer.getElapsedRatio ()); + } + break; + + case S_on: + realAlter (elapsedTime); + break; + + case S_onToOff: + { + if (m_stateTimer.updateZero (elapsedTime)) + m_state = S_off; + else + realAlter (elapsedTime * m_stateTimer.getRemainingRatio ()); + } + break; + } + + // @todo if worthwhile, come up with a way to have this only alter when + // necessary. + // + // For now, alter every frame. + return AlterResult::cms_alterNextFrame; +} + +//------------------------------------------------------------------- + +void StateDynamics::setState (const bool on) +{ + if (on) + m_state = S_offToOn; + else + m_state = S_onToOff; + + m_stateTimer.reset (); +} + +//=================================================================== +// PROTECTED StateDynamics +//=================================================================== + +void StateDynamics::realAlter (const float /*elapsedTime*/) +{ +} + +//=================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.h new file mode 100644 index 00000000..438ad606 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/StateDynamics.h @@ -0,0 +1,59 @@ +//=================================================================== +// +// StateDynamics.h +// asommers 12-12-2000 +// +// a simple dynamics class showing how to use it +// +//=================================================================== + +#ifndef INCLUDED_StateDynamics_H +#define INCLUDED_StateDynamics_H + +//=================================================================== + +#include "sharedFoundation/Timer.h" +#include "sharedObject/Dynamics.h" + +//=================================================================== + +class StateDynamics : public Dynamics +{ +public: + + StateDynamics (Object* owner); + virtual ~StateDynamics (); + + virtual float alter (float elapsedTime); + + void setState (bool on); + +protected: + + virtual void realAlter (float elapsedTime); + +private: + + StateDynamics (); + StateDynamics (const StateDynamics&); + StateDynamics& operator= (const StateDynamics&); + +private: + + enum State + { + S_off, + S_offToOn, + S_on, + S_onToOff + }; + +private: + + State m_state; + Timer m_stateTimer; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.cpp b/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.cpp new file mode 100644 index 00000000..29562236 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.cpp @@ -0,0 +1,91 @@ +// ====================================================================== +// +// TrackingDynamics.cpp +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/TrackingDynamics.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedMath/Vector.h" +#include "sharedObject/Object.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(TrackingDynamics, true, 0, 0, 0); + +// ====================================================================== + +TrackingDynamics::TrackingDynamics(Object *owner, Object const *targetObject, float speed, Vector const &rotationRadiansPerSecond) : + SimpleDynamics(owner), + m_targetWatcher(targetObject), + m_speed(speed), + m_radiansPerSecond(rotationRadiansPerSecond) +{ +} + +// ---------------------------------------------------------------------- + +float TrackingDynamics::alter(float elapsedTime) +{ + Object *const ownerObject = getOwner(); + if (ownerObject) + { + Object const *const targetObject = m_targetWatcher.getPointer(); + if (targetObject) + { + //-- Get world position of owner and target. + Vector const ownerPosition_w = ownerObject->getPosition_w(); + Vector const targetPosition_w = targetObject->getPosition_w(); + + //-- Compute world-space direction vector. + Vector direction_w = targetPosition_w - ownerPosition_w; + IGNORE_RETURN(direction_w.normalize()); + + //-- Set current velocity. + setCurrentVelocity_w(direction_w * m_speed); + } + + //-- Handle object rotation. + ownerObject->yaw_o (m_radiansPerSecond.y * elapsedTime); + ownerObject->pitch_o (m_radiansPerSecond.x * elapsedTime); + ownerObject->roll_o (m_radiansPerSecond.z * elapsedTime); + } + + //-- Chain up alter. This will handle the object translation. + return SimpleDynamics::alter(elapsedTime); +} + +// ---------------------------------------------------------------------- + +void TrackingDynamics::setTarget(Object const *targetObject) +{ + m_targetWatcher = targetObject; +} + +// ---------------------------------------------------------------------- + +float TrackingDynamics::getDistanceToTargetSquared() const +{ + Object const *const ownerObject = getOwner(); + if (ownerObject) + { + Object const *const targetObject = m_targetWatcher.getPointer(); + if (targetObject) + { + //-- Get world position of owner and target. + Vector const ownerPosition_w = ownerObject->getPosition_w(); + Vector const targetPosition_w = targetObject->getPosition_w(); + + return ownerPosition_w.magnitudeBetweenSquared(targetPosition_w); + } + } + + return 0.0f; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.h b/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.h new file mode 100644 index 00000000..70fa5841 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/dynamics/TrackingDynamics.h @@ -0,0 +1,53 @@ +// ====================================================================== +// +// TrackingDynamics.h +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_TrackingDynamics_H +#define INCLUDED_TrackingDynamics_H + +// ====================================================================== + +#include "sharedObject/SimpleDynamics.h" +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedFoundation/Watcher.h" +#include "sharedMath/Vector.h" + +class MemoryBlockManager; + +// ====================================================================== + +class TrackingDynamics: public SimpleDynamics +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + TrackingDynamics(Object *owner, Object const *targetObject, float speed, Vector const &rotationRadiansPerSecond); + + virtual float alter(float elapsedTime); + + void setTarget(Object const *targetObject); + float getDistanceToTargetSquared() const; + +private: + + // Disabled. + TrackingDynamics(); + TrackingDynamics(const TrackingDynamics&); + TrackingDynamics &operator =(const TrackingDynamics&); + +private: + + ConstWatcher m_targetWatcher; + float m_speed; + Vector m_radiansPerSecond; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/lot/LotManager.cpp b/engine/shared/library/sharedObject/src/shared/lot/LotManager.cpp new file mode 100644 index 00000000..eb5ee6bf --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/lot/LotManager.cpp @@ -0,0 +1,536 @@ +//=================================================================== +// +// LotManager.cpp +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/LotManager.h" + +#include "sharedCollision/BoxExtent.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedMath/Rectangle2d.h" +#include "sharedObject/StructureFootprint.h" +#include "sharedObject/World.h" +#include "sharedTerrain/TerrainObject.h" + +#include +#include +#include + +//=================================================================== +// LotManager::NoBuildEntry +//=================================================================== + +LotManager::NoBuildEntry::NoBuildEntry (Vector const & position_w, float radius) : + m_position_w (position_w), + m_radius (radius), + m_spatialSubdivisionHandle (0) +{ +} + +// ---------------------------------------------------------------------- + +LotManager::NoBuildEntry::~NoBuildEntry () +{ +} + +// ---------------------------------------------------------------------- + +Sphere const LotManager::NoBuildEntry::getSphere () const +{ + return Sphere (m_position_w, m_radius); +} + +// ---------------------------------------------------------------------- + +SpatialSubdivisionHandle * LotManager::NoBuildEntry::getSpatialSubdivisionHandle () +{ + return m_spatialSubdivisionHandle; +} + +// ---------------------------------------------------------------------- + +void LotManager::NoBuildEntry::setSpatialSubdivisionHandle (SpatialSubdivisionHandle * const spatialSubdivisionHandle) +{ + m_spatialSubdivisionHandle = spatialSubdivisionHandle; +} + +//=================================================================== +// LotManagerNamespace +//=================================================================== + +namespace LotManagerNamespace +{ + bool ms_logEntries; + bool ms_debugReport; + + void debugReport (void * context) + { + LotManager const * lotManager = reinterpret_cast (context); + if (lotManager) + { + DEBUG_REPORT_PRINT (true, ("-- LotManager\n")); + DEBUG_REPORT_PRINT (true, (" noBuildEntries = %i\n", lotManager->getNumberOfNoBuildEntries ())); + DEBUG_REPORT_PRINT (true, ("structureFootprintEntries = %i\n", lotManager->getNumberOfStructureFootprintEntries ())); + } + } +} + +using namespace LotManagerNamespace; + +//=================================================================== +// PUBLIC LotManager +//=================================================================== + +LotManager::LotManager (const float mapWidthInMeters, const float chunkWidthInMeters) : + m_mapWidthInMeters (mapWidthInMeters), + m_chunkWidthInMeters (chunkWidthInMeters), + m_width (static_cast (mapWidthInMeters / chunkWidthInMeters)), + m_width_2 (m_width / 2), + m_noBuildEntryMap (new NoBuildEntryMap), + m_structureFootprintEntryMap (new StructureFootprintEntryMap) +{ + DebugFlags::registerFlag (ms_logEntries, "SharedObject/LotManager", "logEntries"); + DebugFlags::registerFlag (ms_debugReport, "SharedObject/LotManager", "debugReport", debugReport, this); +} + +//------------------------------------------------------------------- + +LotManager::~LotManager () +{ + DebugFlags::unregisterFlag (ms_logEntries); + DebugFlags::unregisterFlag (ms_debugReport); + + DEBUG_WARNING (!m_noBuildEntryMap->empty (), ("LotManager::~LotManager: m_noBuildEntryMap is not empty")); + std::for_each (m_noBuildEntryMap->begin (), m_noBuildEntryMap->end (), PointerDeleterPairSecond ()); + delete m_noBuildEntryMap; + + DEBUG_WARNING (!m_structureFootprintEntryMap->empty (), ("LotManager::~LotManager: m_structureFootprintEntryMap is not empty")); + delete m_structureFootprintEntryMap; +} + +//------------------------------------------------------------------- + +void LotManager::addNoBuildEntry (Object const & object, float const noBuildRadius) +{ + NOT_NULL (m_noBuildEntryMap); + + Vector position_w = object.getPosition_w (); + position_w.y = 0.f; + + NoBuildEntry * const noBuildEntry = new NoBuildEntry (position_w, noBuildRadius); + noBuildEntry->setSpatialSubdivisionHandle (m_sphereTree.addObject (noBuildEntry)); + + bool const result = m_noBuildEntryMap->insert (std::make_pair (&object, noBuildEntry)).second; + UNREF (result); + DEBUG_FATAL (!result, ("LotManager::addNoBuildEntry - entry already exists")); + DEBUG_REPORT_LOG (ms_logEntries, ("LotManager: added no build entry for object %s [%s] at <%1.2f, %1.2f>\n", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName () ? object.getObjectTemplateName () : "null", position_w.x, position_w.z)); +} + +//------------------------------------------------------------------- + +void LotManager::removeNoBuildEntry (const Object& object) +{ + NoBuildEntryMap::iterator iter = m_noBuildEntryMap->find (&object); + NoBuildEntryMap::iterator end = m_noBuildEntryMap->end (); + if (iter != end) + { + NoBuildEntry * const noBuildEntry = iter->second; + + m_sphereTree.removeObject (noBuildEntry->getSpatialSubdivisionHandle ()); + delete noBuildEntry; + + IGNORE_RETURN (m_noBuildEntryMap->erase (iter)); + } + else + DEBUG_FATAL (true, ("LotManager::removeNoBuildEntry - entry not found")); + + DEBUG_REPORT_LOG (ms_logEntries, ("LotManager: removed no build entry for object %s [%s]\n", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName () ? object.getObjectTemplateName () : "null")); +} + +//------------------------------------------------------------------- + +int LotManager::getNumberOfNoBuildEntries () const +{ + NOT_NULL (m_noBuildEntryMap); + + return static_cast (m_noBuildEntryMap->size ()); +} + +//------------------------------------------------------------------- + +void LotManager::addStructureFootprintEntry (const Object& object, const StructureFootprint& structureFootprint, const int x, const int z, const RotationType rotation) +{ + NOT_NULL (m_structureFootprintEntryMap); + + StructureFootprintEntry structureFootprintEntry; + structureFootprintEntry.m_structureFootprint = &structureFootprint; + structureFootprintEntry.m_x = x; + structureFootprintEntry.m_z = z; + structureFootprintEntry.m_rotation = rotation; + const bool result = m_structureFootprintEntryMap->insert (std::make_pair (&object, structureFootprintEntry)).second; + UNREF (result); + DEBUG_FATAL (!result, ("LotManager::addStructureFootprintEntry - entry already exists")); + + DEBUG_REPORT_LOG (ms_logEntries, ("LotManager: added structure footprint entry for object %s [%s] at <%1.2f, %1.2f>\n", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName () ? object.getObjectTemplateName () : "null", x * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.5f, z * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.5f)); +} + +//------------------------------------------------------------------- + +void LotManager::removeStructureFootprintEntry (const Object& object) +{ + StructureFootprintEntryMap::iterator iter = m_structureFootprintEntryMap->find (&object); + StructureFootprintEntryMap::iterator end = m_structureFootprintEntryMap->end (); + if (iter != end) + IGNORE_RETURN (m_structureFootprintEntryMap->erase (iter)); + else + DEBUG_FATAL (true, ("LotManager::removeStructureFootprintEntry - entry not found")); + + DEBUG_REPORT_LOG (ms_logEntries, ("LotManager: removed structure footprint entry for object %s [%s]\n", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName () ? object.getObjectTemplateName () : "null")); +} + +//------------------------------------------------------------------- + +int LotManager::getNumberOfStructureFootprintEntries () const +{ + NOT_NULL (m_structureFootprintEntryMap); + + return static_cast (m_structureFootprintEntryMap->size ()); +} + +//------------------------------------------------------------------- + +bool LotManager::canPlace (const StructureFootprint* const structureFootprint, const int x, const int z, const RotationType rotation, float& height_w, bool const forceChunkCreation) const +{ + NOT_NULL (structureFootprint); + + BoxExtent boxExtent; + boxExtent.setMin (Vector::maxXYZ); + boxExtent.setMax (Vector::negativeMaxXYZ); + + switch (rotation) + { + default: + case RT_0: + { + const int pivotX = structureFootprint->getPivotX (); + const int pivotZ = structureFootprint->getPivotZ (); + + int sj = structureFootprint->getHeight () - 1; + int j; + for (j = 0; j < structureFootprint->getHeight (); ++j) + { + int si = 0; + int i; + for (i = 0; i < structureFootprint->getWidth (); ++i) + { + if (!canPlace (boxExtent, (x - pivotX) + i, (z - pivotZ) + j, structureFootprint, si, sj, forceChunkCreation)) + return false; + + ++si; + } + + --sj; + } + } + break; + + case RT_90: + { + const int pivotX = structureFootprint->getPivotZ (); + const int pivotZ = structureFootprint->getPivotX (); + + int sj = structureFootprint->getWidth () - 1; + int j; + for (j = 0; j < structureFootprint->getWidth (); ++j) + { + int si = structureFootprint->getHeight () - 1; + int i; + for (i = 0; i < structureFootprint->getHeight (); ++i) + { + if (!canPlace (boxExtent, (x - pivotX) + i, (z - (structureFootprint->getWidth () - 1 - pivotZ)) + j, structureFootprint, sj, si, forceChunkCreation)) + return false; + + --si; + } + + --sj; + } + } + break; + + case RT_180: + { + const int pivotX = structureFootprint->getPivotX (); + const int pivotZ = (structureFootprint->getHeight () - 1) - structureFootprint->getPivotZ (); + + int sj = 0; + int j; + for (j = 0; j < structureFootprint->getHeight (); ++j) + { + int si = structureFootprint->getWidth () - 1; + int i; + for (i = 0; i < structureFootprint->getWidth (); ++i) + { + if (!canPlace (boxExtent, (x - (structureFootprint->getWidth () - 1 - pivotX)) + i, (z - pivotZ) + j, structureFootprint, si, sj, forceChunkCreation)) + return false; + + --si; + } + + ++sj; + } + } + break; + + case RT_270: + { + const int pivotX = (structureFootprint->getHeight () - 1) - structureFootprint->getPivotZ (); + const int pivotZ = structureFootprint->getPivotX (); + + int sj = 0; + int j; + for (j = 0; j < structureFootprint->getWidth (); ++j) + { + int si = 0; + int i; + for (i = 0; i < structureFootprint->getHeight (); ++i) + { + if (!canPlace (boxExtent, (x - pivotX) + i, (z - pivotZ) + j, structureFootprint, sj, si, forceChunkCreation)) + return false; + + ++si; + } + + ++sj; + } + } + break; + } + + if (boxExtent.getHeight() < 0.0f) + { + WARNING(true, ("LotManager invalid boxExtent")); + return false; + } + + //-- if box extent is smaller than the tolerance, we're ok + if (boxExtent.getHeight () > structureFootprint->getStructureReservationTolerance ()) + return false; + + height_w = boxExtent.getTop (); + + return true; +} + +//------------------------------------------------------------------- + +bool LotManager::canPlace (Rectangle2d const & rectangle2d) const +{ + const int x0 = TerrainObject::getConstInstance ()->calculateChunkX (Vector (rectangle2d.x0, 0.f, rectangle2d.y0)); + const int z0 = TerrainObject::getConstInstance ()->calculateChunkZ (Vector (rectangle2d.x0, 0.f, rectangle2d.y0)); + const int x1 = TerrainObject::getConstInstance ()->calculateChunkX (Vector (rectangle2d.x1, 0.f, rectangle2d.y1)); + const int z1 = TerrainObject::getConstInstance ()->calculateChunkZ (Vector (rectangle2d.x1, 0.f, rectangle2d.y1)); + + int x; + int z; + for (z = z0; z <= z1; ++z) + for (x = x0; x <= x1; ++x) + if (getLotType (x, z) == LT_illegal) + return false; + + return true; +} + +//------------------------------------------------------------------- + +int LotManager::getWidth () const +{ + return m_width; +} + +//------------------------------------------------------------------- + +LotType LotManager::getLotType (const int x, const int z) const +{ + //-- all we want to know is if the lot is occupied + if (x < -m_width_2 || x >= m_width_2 || z < -m_width_2 || z >= m_width_2) + return LT_illegal; + + //-- go through the no build entries + { + const Vector position_w (x * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.5f, 0.f, z * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.5f); + + if (m_sphereTree.isWithin (position_w)) + return LT_illegal; + } + + //-- go through the structure footprint entries + { + StructureFootprintEntryMap::iterator iter = m_structureFootprintEntryMap->begin (); + StructureFootprintEntryMap::iterator end = m_structureFootprintEntryMap->end (); + for (; iter != end; ++iter) + { + const StructureFootprintEntry& structureFootprintEntry = iter->second; + + switch (structureFootprintEntry.m_rotation) + { + default: + case RT_0: + { + const int pivotX = structureFootprintEntry.m_structureFootprint->getPivotX (); + const int pivotZ = structureFootprintEntry.m_structureFootprint->getPivotZ (); + + const int minX = structureFootprintEntry.m_x - pivotX; + const int maxX = minX + structureFootprintEntry.m_structureFootprint->getWidth (); + const int minZ = structureFootprintEntry.m_z - pivotZ; + const int maxZ = minZ + structureFootprintEntry.m_structureFootprint->getHeight (); + + if (x >= minX && x < maxX && z >= minZ && z < maxZ) + { + const int sx = x - minX; + const int sz = (structureFootprintEntry.m_structureFootprint->getHeight () - 1) - (z - minZ); + + const LotType lotType = structureFootprintEntry.m_structureFootprint->getLotType (sx, sz); + + if (lotType == LT_hard || lotType == LT_structure) + return LT_illegal; + } + } + break; + + case RT_90: + { + const int pivotX = structureFootprintEntry.m_structureFootprint->getPivotZ (); + const int pivotZ = structureFootprintEntry.m_structureFootprint->getPivotX (); + + const int minX = structureFootprintEntry.m_x - pivotX; + const int maxX = minX + structureFootprintEntry.m_structureFootprint->getHeight (); + const int minZ = structureFootprintEntry.m_z - (structureFootprintEntry.m_structureFootprint->getWidth () - 1 - pivotZ); + const int maxZ = minZ + structureFootprintEntry.m_structureFootprint->getWidth (); + + if (x >= minX && x < maxX && z >= minZ && z < maxZ) + { + const int sx = (structureFootprintEntry.m_structureFootprint->getHeight () - 1) - (x - minX); + const int sz = (structureFootprintEntry.m_structureFootprint->getWidth () - 1) - (z - minZ); + + const LotType lotType = structureFootprintEntry.m_structureFootprint->getLotType (sz, sx); + + if (lotType == LT_hard || lotType == LT_structure) + return LT_illegal; + } + } + break; + + case RT_180: + { + const int pivotX = structureFootprintEntry.m_structureFootprint->getPivotX (); + const int pivotZ = (structureFootprintEntry.m_structureFootprint->getHeight () - 1) - structureFootprintEntry.m_structureFootprint->getPivotZ (); + + const int minX = structureFootprintEntry.m_x - (structureFootprintEntry.m_structureFootprint->getWidth () - 1 - pivotX); + const int maxX = minX + structureFootprintEntry.m_structureFootprint->getWidth (); + const int minZ = structureFootprintEntry.m_z - pivotZ; + const int maxZ = minZ + structureFootprintEntry.m_structureFootprint->getHeight (); + + if (x >= minX && x < maxX && z >= minZ && z < maxZ) + { + const int sx = (structureFootprintEntry.m_structureFootprint->getWidth () - 1) - (x - minX); + const int sz = z - minZ; + + const LotType lotType = structureFootprintEntry.m_structureFootprint->getLotType (sx, sz); + + if (lotType == LT_hard || lotType == LT_structure) + return LT_illegal; + } + } + break; + + case RT_270: + { + const int pivotX = (structureFootprintEntry.m_structureFootprint->getHeight () - 1) - structureFootprintEntry.m_structureFootprint->getPivotZ (); + const int pivotZ = structureFootprintEntry.m_structureFootprint->getPivotX (); + + const int minX = structureFootprintEntry.m_x - pivotX; + const int maxX = minX + structureFootprintEntry.m_structureFootprint->getHeight (); + const int minZ = structureFootprintEntry.m_z - pivotZ; + const int maxZ = minZ + structureFootprintEntry.m_structureFootprint->getWidth (); + + if (x >= minX && x < maxX && z >= minZ && z < maxZ) + { + const int sx = x - minX; + const int sz = z - minZ; + + const LotType lotType = structureFootprintEntry.m_structureFootprint->getLotType (sz, sx); + + if (lotType == LT_hard || lotType == LT_structure) + return LT_illegal; + } + } + break; + } + } + } + + return LT_nothing; +} + +//=================================================================== +// PRIVATE LotManager +//=================================================================== + +bool LotManager::canPlace (BoxExtent& boxExtent, const int x, const int z, const StructureFootprint* const structureFootprint, const int structureX, const int structureZ, bool const forceChunkCreation) const +{ + const TerrainObject* const terrainObject = TerrainObject::getConstInstance (); + if (!terrainObject) + { + DEBUG_WARNING (true, ("LotManager::canPlace - no terrain")); + return false; + } + + //-- verify not in water + if (terrainObject->getWater (x, z)) + return false; + + //-- check lot types and grow extent + const LotType sourceLotType = structureFootprint->getLotType (structureX, structureZ); + const LotType destinationLotType = getLotType (x, z); + const Vector position_w (x * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.495f, 0.f, z * m_chunkWidthInMeters + m_chunkWidthInMeters * 0.495f); + const BoxExtent* const chunkExtent = forceChunkCreation ? terrainObject->getChunkExtentForceChunkCreation (position_w) : terrainObject->getChunkExtent (position_w); + if (!chunkExtent) + { + DEBUG_WARNING (true, ("LotManager::canPlace - could not find extent for <%1.2f, %1.2f>\n", position_w.x, position_w.z)); + return false; + } + + bool ok = false; + bool growExtent = false; + + if (sourceLotType == LT_nothing) + ok = true; + + if (sourceLotType == LT_hard && destinationLotType == LT_nothing) + { + ok = true; + growExtent = true; + } + + if (sourceLotType == LT_structure && destinationLotType == LT_nothing) + { + ok = true; + growExtent = true; + } + + bool const updateBoxExtent = structureFootprint->getBoxTestRect().isWithin(static_cast(structureX), static_cast(structureZ)); + if (updateBoxExtent && growExtent) + boxExtent.grow (*chunkExtent); + + return ok; +} + +//=================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/lot/LotManager.h b/engine/shared/library/sharedObject/src/shared/lot/LotManager.h new file mode 100644 index 00000000..22a62e09 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/lot/LotManager.h @@ -0,0 +1,138 @@ +//=================================================================== +// +// LotManager.h +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_LotManager_H +#define INCLUDED_LotManager_H + +//=================================================================== + +class BoxExtent; +class Object; +class Rectangle2d; +class SpatialSubdivisionHandle; +class StructureFootprint; + +#include "sharedMath/SphereTree.h" +#include "sharedMath/Vector.h" +#include "sharedObject/LotType.h" + +//=================================================================== + +class LotManager +{ +public: + + LotManager (float mapWidthInMeters, float chunkWidthInMeters); + ~LotManager (); + + void addNoBuildEntry (const Object& object, float noBuildRadius); + void removeNoBuildEntry (const Object& object); + int getNumberOfNoBuildEntries () const; + + void addStructureFootprintEntry (const Object& object, const StructureFootprint& structureFootprint, int x, int z, RotationType rotation); + void removeStructureFootprintEntry (const Object& object); + int getNumberOfStructureFootprintEntries () const; + + bool canPlace (const StructureFootprint* structureFootprint, int x, int z, RotationType rotation, float& height_w, bool forceChunkCreation=true) const; + bool canPlace (Rectangle2d const & rectangle2d) const; + + //-- tool interface + int getWidth () const; + LotType getLotType (int x, int z) const; + +private: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class NoBuildEntry + { + public: + + NoBuildEntry (Vector const & position_w, float radius); + ~NoBuildEntry (); + + Sphere const getSphere () const; + SpatialSubdivisionHandle * getSpatialSubdivisionHandle (); + void setSpatialSubdivisionHandle (SpatialSubdivisionHandle * spatialSubdivisionHandle); + + private: + + NoBuildEntry (NoBuildEntry const & rhs); + NoBuildEntry & operator = (NoBuildEntry const & rhs); + + private: + + Vector const m_position_w; + float const m_radius; + + SpatialSubdivisionHandle * m_spatialSubdivisionHandle; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class NoBuildEntrySphereExtentAccessor: public BaseSphereTreeAccessor + { + public: + + static Sphere const getExtent(NoBuildEntry const * const noBuildEntry) + { + return noBuildEntry ? noBuildEntry->getSphere () : Sphere::zero; + } + + static char const *getDebugName(NoBuildEntry const * const /*noBuildEntry*/) + { + return 0; + } + + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class StructureFootprintEntry + { + public: + + const StructureFootprint* m_structureFootprint; + int m_x; + int m_z; + RotationType m_rotation; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + bool canPlace (BoxExtent& boxExtent, int x, int z, const StructureFootprint* structureFootprint, int structureX, int structureZ, bool forceChunkCreation) const; + +private: + + LotManager (); + LotManager (const LotManager&); + LotManager& operator= (const LotManager&); + +private: + + const float m_mapWidthInMeters; + const float m_chunkWidthInMeters; + const int m_width; + const int m_width_2; + + typedef stdmap::fwd NoBuildEntryMap; + NoBuildEntryMap* const m_noBuildEntryMap; + + typedef stdmap::fwd StructureFootprintEntryMap; + StructureFootprintEntryMap* const m_structureFootprintEntryMap; + + SphereTree m_sphereTree; + +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/lot/LotType.h b/engine/shared/library/sharedObject/src/shared/lot/LotType.h new file mode 100644 index 00000000..c0040c44 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/lot/LotType.h @@ -0,0 +1,35 @@ +//=================================================================== +// +// LotType.h +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_LotType_H +#define INCLUDED_LotType_H + +//=================================================================== + +enum LotType +{ + LT_nothing, + LT_hard, + LT_structure, + LT_illegal +}; + +//------------------------------------------------------------------- + +enum RotationType +{ + RT_0, + RT_90, + RT_180, + RT_270 +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.cpp b/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.cpp new file mode 100644 index 00000000..65dfaf07 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.cpp @@ -0,0 +1,306 @@ +//=================================================================== +// +// StructureFootprint.cpp +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/StructureFootprint.h" + +#include "sharedFile/Iff.h" + +#include + +//=================================================================== + +namespace StructureFootprintLoaderNamespace +{ + const Tag TAG_FOOT = TAG (F,O,O,T); + const Tag TAG_PRNT = TAG (P,R,N,T); +} + +using namespace StructureFootprintLoaderNamespace; + +//=================================================================== +// PUBLIC StructureFootprint +//=================================================================== + +StructureFootprint::StructureFootprint () : + m_width (1), + m_height (1), + m_boxTestRect(), + m_pivotX (0), + m_pivotZ (0), + m_data (new LotType [1]), + m_hardReservationTolerance (1.f), + m_structureReservationTolerance (1.f), + m_numberOfReservations (1), + m_numberOfHardReservations (0), + m_numberOfStructureReservations (1) +{ + //-- the default reservation takes up just lot itself + m_data [0] = LT_structure; +} + +//------------------------------------------------------------------- + +StructureFootprint::~StructureFootprint () +{ + delete [] m_data; + m_data = 0; +} + +//------------------------------------------------------------------- + +void StructureFootprint::load (const char* const filename) +{ + delete [] m_data; + m_data = 0; + + Iff iff; + if (iff.open (filename, true)) + load (iff); + else + DEBUG_WARNING (true, ("StructureFootprint::load - %s not found", filename)); +} + +//------------------------------------------------------------------- + +int StructureFootprint::getWidth () const +{ + return m_width; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getHeight () const +{ + return m_height; +} + +//------------------------------------------------------------------- + +Rectangle2d const & StructureFootprint::getBoxTestRect () const +{ + return m_boxTestRect; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getPivotX () const +{ + return m_pivotX; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getPivotZ () const +{ + return m_pivotZ; +} + +//------------------------------------------------------------------- + +LotType StructureFootprint::getLotType (int x, int z) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, x, m_width); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, z, m_height); + + return m_data [m_width * z + x]; +} + +//------------------------------------------------------------------- + +float StructureFootprint::getHardReservationTolerance () const +{ + return m_hardReservationTolerance; +} + +//------------------------------------------------------------------- + +float StructureFootprint::getStructureReservationTolerance () const +{ + return m_structureReservationTolerance; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getNumberOfReservations () const +{ + return m_numberOfReservations; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getNumberOfHardReservations () const +{ + return m_numberOfHardReservations; +} + +//------------------------------------------------------------------- + +int StructureFootprint::getNumberOfStructureReservations () const +{ + return m_numberOfStructureReservations; +} + +//------------------------------------------------------------------- + +void StructureFootprint::getBorder (int x, int z, bool& top, bool& bottom, bool& left, bool& right) const +{ + top = false; + bottom = false; + left = false; + right = false; + + const bool center = getLotType (x, z) == LT_structure; + const bool outOfRangeTop = z < 0 + 1; + const bool outOfRangeBottom = z >= m_height - 1; + const bool outOfRangeLeft = x < 0 + 1; + const bool outOfRangeRight = x >= m_width - 1; + + if (center) + { + top = outOfRangeTop || (!outOfRangeTop && getLotType (x, z - 1) != LT_structure); + bottom = outOfRangeBottom || (!outOfRangeBottom && getLotType (x, z + 1) != LT_structure); + left = outOfRangeLeft || (!outOfRangeLeft && getLotType (x - 1, z ) != LT_structure); + right = outOfRangeRight || (!outOfRangeRight && getLotType (x + 1, z ) != LT_structure); + } +} + +//=================================================================== +// PRIVATE StructureFootprint +//=================================================================== + +void StructureFootprint::load (Iff& iff) +{ + iff.enterForm (TAG_FOOT); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("StructureFootprint::load - unknown version %s/%s", buffer, tagBuffer)); + } + break; + } + + iff.exitForm (TAG_FOOT); +} + +//------------------------------------------------------------------- + +void StructureFootprint::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- + iff.enterChunk (TAG_INFO); + + m_width = iff.read_int32 (); + DEBUG_FATAL (m_width == 0, ("width == 0")); + m_height = iff.read_int32 (); + DEBUG_FATAL (m_height == 0, ("height == 0")); + + m_pivotX = iff.read_int32 (); + m_pivotZ = iff.read_int32 (); + m_hardReservationTolerance = iff.read_float (); + m_structureReservationTolerance = iff.read_float (); + + iff.exitChunk (TAG_INFO); + + m_boxTestRect.x0 = m_boxTestRect.y0 = 0.0f; + m_boxTestRect.x1 = static_cast(m_width); + m_boxTestRect.y1 = static_cast(m_height); + + if (iff.enterChunk(TAG_DATA, true)) + { + m_boxTestRect.x0 = static_cast(iff.read_int32()); + m_boxTestRect.y0 = static_cast(iff.read_int32()); + m_boxTestRect.x1 = static_cast(iff.read_int32()); + m_boxTestRect.y1 = static_cast(iff.read_int32()); + + iff.exitChunk(TAG_DATA); + } + + //-- + iff.enterChunk (TAG_PRNT); + + std::string footprint; + + int i; + for (i = 0; i < m_height; ++i) + { + DEBUG_FATAL (iff.getChunkLengthLeft () == 0, ("StructureFootprintLoader::load_0000 [%s]: height mismatch", iff.getFileName ())); + + char* buffer = iff.read_string (); + DEBUG_FATAL (istrlen (buffer) != m_width, ("StructureFootprintLoader::load_0000 [%s]: width mismatch", iff.getFileName ())); + + const std::string tempFootprint = footprint + buffer; + footprint = tempFootprint; + + delete [] buffer; + } + + iff.exitChunk (TAG_PRNT); + + //-- allocate footprint + IS_NULL (m_data); + m_data = new LotType [static_cast (m_width * m_height)]; + NOT_NULL (m_data); + + //-- convert string to footprint + const char* const buffer = footprint.c_str (); + + m_numberOfReservations = 0; + m_numberOfHardReservations = 0; + m_numberOfStructureReservations = 0; + + const int n = m_width * m_height; + for (i = 0; i < n; ++i) + { + switch (buffer [i]) + { + case 'F': + case 'f': + m_data [i] = LT_structure; + ++m_numberOfReservations; + ++m_numberOfStructureReservations; + break; + + case 'H': + case 'h': + m_data [i] = LT_hard; + ++m_numberOfReservations; + ++m_numberOfHardReservations; + break; + + case '.': + m_data [i] = LT_nothing; + break; + + default: + m_data [i] = LT_hard; + ++m_numberOfReservations; + ++m_numberOfHardReservations; + DEBUG_WARNING (true, ("StructureFootprintLoader::load [%s] - unknown lot type %c", iff.getFileName (), buffer [i])); + break; + } + } + + iff.exitForm (TAG_0000); +} + +//=================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.h b/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.h new file mode 100644 index 00000000..d1dd414e --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/lot/StructureFootprint.h @@ -0,0 +1,73 @@ +//=================================================================== +// +// StructureFootprint.h +// asommers +// +// copyright 2002, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_StructureFootprint_H +#define INCLUDED_StructureFootprint_H + +//=================================================================== + +#include "sharedObject/LotType.h" +#include "sharedMath/Rectangle2d.h" + +class Iff; + +//=================================================================== + +class StructureFootprint +{ +public: + + StructureFootprint (); + ~StructureFootprint (); + + void load (const char* filename); + + int getWidth () const; + int getHeight () const; + + Rectangle2d const & getBoxTestRect () const; + + int getPivotX () const; + int getPivotZ () const; + LotType getLotType (int x, int z) const; + float getHardReservationTolerance () const; + float getStructureReservationTolerance () const; + int getNumberOfReservations () const; + int getNumberOfHardReservations () const; + int getNumberOfStructureReservations () const; + void getBorder (int x, int z, bool& top, bool& bottom, bool& left, bool& right) const; + +private: + + void load (Iff& iff); + void load_0000 (Iff& iff); + +private: + + StructureFootprint (const StructureFootprint&); + StructureFootprint& operator= (const StructureFootprint&); + +private: + + int m_width; + int m_height; + Rectangle2d m_boxTestRect; + int m_pivotX; + int m_pivotZ; + LotType* m_data; + float m_hardReservationTolerance; + float m_structureReservationTolerance; + int m_numberOfReservations; + int m_numberOfHardReservations; + int m_numberOfStructureReservations; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/movement/MovementTable.cpp b/engine/shared/library/sharedObject/src/shared/movement/MovementTable.cpp new file mode 100644 index 00000000..e14739f2 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/movement/MovementTable.cpp @@ -0,0 +1,493 @@ +// ====================================================================== +// +// MovementTable.cpp +// Copyright 2002-2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/MovementTable.h" + +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "swgSharedUtility/Postures.h" +#include "swgSharedUtility/States.h" + +#include + +// ====================================================================== + +namespace MovementTableNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::map StateFloatMap; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + char const *const cs_stateRateModifierFilename = "datatables/movement/state_rate_modifiers.iff"; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + StateFloatMap s_stateMovementRateModifiers; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + inline bool hasState(uint64 flags, States::Enumerator state) + { + return (flags & States::getStateMask(state)) != 0; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace MovementTableNamespace; + +// ====================================================================== + +struct MovementTable::rates +{ + Locomotions::Enumerator stationary; + Locomotions::Enumerator slow; + Locomotions::Enumerator fast; + float move; + float accel; + float turn; + float canSeeHeightMod; +}; + +// ====================================================================== + +bool MovementTable::ms_installed; +MovementTable::eLocomotionSpeed MovementTable::ms_stateMoveLimit[States::NumberOfStates]; + +// ====================================================================== +// class MovementTable: PUBLIC STATIC +// ====================================================================== + +void MovementTable::install(const std::string &stateFileName) +{ + DEBUG_FATAL(ms_installed, ("MovementTable already installed")); + + //-- Process state locomotion speed limit file. + { + DataTable *table = DataTableManager::getTable(stateFileName, true); + FATAL(!table, ("Couldn't open movement state datatable [%s]", stateFileName.c_str())); + + int i; + for (i = 0; i < States::NumberOfStates; ++i) + ms_stateMoveLimit[i] = kFast; + + int const rowCount = table->getNumRows(); + + for (i = 0; i < rowCount; ++i) + { + States::Enumerator state = static_cast(table->getIntValue("state", i)); + ms_stateMoveLimit[state] = static_cast(table->getIntValue("maxSpeedCategory", i)); + } + DataTableManager::close(stateFileName); + } + + //-- Process state movement rate modifiers file. + { + s_stateMovementRateModifiers.clear(); + + // @todo -TRF- get filename from caller. + char const *filename = cs_stateRateModifierFilename; + + DataTable *table = DataTableManager::getTable(filename, true); + FATAL(!table, ("Couldn't open state movement rate modifier datatable [%s].", filename)); + + int const rowCount = table->getNumRows(); + + for (int i = 0; i < rowCount; ++i) + { + States::Enumerator const state = static_cast(table->getIntValue("state", i)); + float const rateModifier = table->getFloatValue("movementRateModifier", i); + + IGNORE_RETURN(s_stateMovementRateModifiers.insert(StateFloatMap::value_type(state, rateModifier))); + } + DataTableManager::close(filename); + } + + ms_installed = true; +} + +// ====================================================================== +// class MovementTable: PUBLIC +// ====================================================================== + +MovementTable::MovementTable (const std::string &filename, const std::string &templateName) : + m_postures(new PostureMap) +{ + DataTable * table = DataTableManager::getTable(filename, true); + UNREF(templateName); + FATAL(!table, ("Couldn't open movement datatable [%s] for template [%s]", filename.c_str(), templateName.c_str())); + + int x; + for (x=0; xgetNumRows(); ++x) + { + Postures::Enumerator posture = static_cast(table->getIntValue("posture", x)); + rates temp; + + temp.stationary = static_cast(table->getIntValue("stationary", x)); + temp.slow = static_cast(table->getIntValue("slow", x)); + temp.fast = static_cast(table->getIntValue("fast", x)); + + temp.move = table->getFloatValue("movementScale", x); + temp.accel = table->getFloatValue("accelerationScale", x); + temp.turn = table->getFloatValue("turnScale", x); + temp.canSeeHeightMod = table->getFloatValue("canSeeHeightMod", x); + + (*m_postures)[posture] = temp; + if (temp.stationary != Locomotions::Invalid) + m_locomotionPostures[temp.stationary] = posture; + if (temp.slow != Locomotions::Invalid) + m_locomotionPostures[temp.slow] = posture; + if (temp.fast != Locomotions::Invalid) + m_locomotionPostures[temp.fast] = posture; + } + table = 0; +} + +// ---------------------------------------------------------------------- + +MovementTable::~MovementTable (void) +{ + delete m_postures; +} + +// ---------------------------------------------------------------------- + +MovementTable::eLocomotionSpeed MovementTable::getLocomotionData(Locomotions::Enumerator locomotion, Postures::Enumerator &o_posture) const +{ + if (locomotion < 0 || locomotion >= Locomotions::NumberOfLocomotions) + return kInvalid; + + o_posture = m_locomotionPostures[locomotion]; + if (o_posture == Postures::Invalid) + return kInvalid; + + return getPostureSpeed(o_posture, locomotion); +} + +// ---------------------------------------------------------------------- + +MovementTable::eLocomotionSpeed MovementTable::getPostureSpeed(Postures::Enumerator i_posture, Locomotions::Enumerator i_locomotion) const +{ + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return kInvalid; + + const rates &rate = m_postures->find(i_posture)->second; + if (rate.fast == i_locomotion) + return kFast; + + if (rate.slow == i_locomotion) + return kSlow; + + DEBUG_FATAL(rate.stationary != i_locomotion, ("Bad movement rate setup. See a programmer")); + return kStationary; +} + +// ---------------------------------------------------------------------- + +Locomotions::Enumerator MovementTable::getLocomotion(Postures::Enumerator i_posture, uint64 i_states, MovementTable::eLocomotionSpeed i_speed) const +{ + //-- Validate posture arg. + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return Locomotions::Invalid; + + //-- Lookup base rates for posture. + PostureMap::const_iterator f = m_postures->find(i_posture); + if (f == m_postures->end()) + return Locomotions::Invalid; + + const rates &rate = f->second; + + //-- Adjust locomotion speed for the prevailing states. + eLocomotionSpeed speed = adjustSpeedForStates(i_speed, i_states); + + //-- Return the appropriate rate based on locomotion speed. + Locomotions::Enumerator locomotion = Locomotions::Invalid; + + switch (i_speed) + { + case kInvalid: + locomotion = Locomotions::Invalid; + break; + + case kStationary: + locomotion = rate.stationary; + break; + + case kSlow: + if (speed >= kSlow) + locomotion = rate.slow; + break; + + case kFast: + if (speed >= kFast) + locomotion = rate.fast; + break; + } + + return locomotion; +} + +// ---------------------------------------------------------------------- + +void MovementTable::getAllLocomotions(Postures::Enumerator i_posture, uint64 i_states, Locomotions::Enumerator &fastLocomotion, Locomotions::Enumerator &slowLocomotion, Locomotions::Enumerator &stationaryLocomotion) const +{ + //-- Initialize to invalid. + fastLocomotion = Locomotions::Invalid; + slowLocomotion = Locomotions::Invalid; + stationaryLocomotion = Locomotions::Invalid; + + //-- Validate posture arg. + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return; + + //-- Lookup base rates for posture. + PostureMap::const_iterator f = m_postures->find(i_posture); + if (f == m_postures->end()) + return; + + const rates &rate = f->second; + + //-- Retrieve locomotion for each rate if that rate is supported. + if (adjustSpeedForStates(kFast, i_states) >= kFast) + fastLocomotion = rate.fast; + + if (adjustSpeedForStates(kSlow, i_states) >= kSlow) + slowLocomotion = rate.slow; + + stationaryLocomotion = rate.stationary; +} + +// ---------------------------------------------------------------------- + +bool MovementTable::getRates(Postures::Enumerator i_posture, float &o_moveScale, float &o_accelScale, float &o_turnScale) const +{ + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return false; + + PostureMap::const_iterator f = m_postures->find(i_posture); + if (f == m_postures->end()) + return false; + + const rates &rate = f->second; + + o_moveScale = rate.move; + o_turnScale = rate.turn; + o_accelScale = rate.accel; + + return true; +} + +// ---------------------------------------------------------------------- + +bool MovementTable::hasMovingLocomotion(Postures::Enumerator i_posture, uint64 i_states) const +{ + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return false; + + if (adjustSpeedForStates(kFast, i_states) == kStationary) + return false; + + const rates &rate = m_postures->find(i_posture)->second; + return (rate.fast != Locomotions::Invalid) || (rate.slow != Locomotions::Invalid); +} + +// ---------------------------------------------------------------------- + +float MovementTable::getSlowMoveRate(Postures::Enumerator i_posture, uint64 i_states) const +{ + //-- Validate posture arg. + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return 0.0f; + + //-- Check if state speed adjustment causes us to stop moving. + if (adjustSpeedForStates(kSlow, i_states) < kSlow) + return 0.0f; + + //-- Lookup rate table for posture. + PostureMap::iterator findIt = m_postures->find(i_posture); + if (findIt == m_postures->end()) + { + DEBUG_WARNING(true, ("MovementTable::getSlowMoveRate(): failed to find rate table entry for posture id=[%s],name=[%s], will return 0 rate.", i_posture, Postures::getPostureName(i_posture))); + return 0.0f; + } + + const rates &rate = findIt->second; + + //-- Start with the fast movement rate. + float const baseRate = (rate.slow != Locomotions::Invalid) ? rate.move : 0.0f; + + //-- Retrieve state rate modifiers. + float const stateRateModifier = getMovementRateModifierForStates(i_states); + + float const finalRate = baseRate * stateRateModifier; + return finalRate; +} + +// ---------------------------------------------------------------------- + +float MovementTable::getFastMoveRate(Postures::Enumerator i_posture, uint64 i_states) const +{ + //-- Validate posture arg. + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return 0.0f; + + //-- Check if state speed adjustment causes us to stop moving. + if (adjustSpeedForStates(kFast, i_states) <= kSlow) + return 0.0f; + + //-- Lookup rate table for posture. + PostureMap::iterator findIt = m_postures->find(i_posture); + if (findIt == m_postures->end()) + { + DEBUG_WARNING(true, ("MovementTable::getFastMoveRate(): failed to find rate table entry for posture id=[%s],name=[%s], will return 0 rate.", i_posture, Postures::getPostureName(i_posture))); + return 0.0f; + } + + const rates &rate = findIt->second; + + //-- Start with the fast movement rate. + float const baseRate = (rate.fast != Locomotions::Invalid) ? rate.move : 0.0f; + + //-- Retrieve state rate modifiers. + float const stateRateModifier = getMovementRateModifierForStates(i_states); + + float const finalRate = baseRate * stateRateModifier; + return finalRate; +} + +// ---------------------------------------------------------------------- + +void MovementTable::getAllMovementRateScales(Postures::Enumerator posture, uint64 states, float &slowMoveRateScale, float &fastMoveRateScale, float &accelerationScale, float &turnScale) const +{ + //-- Lookup rate table for posture. + PostureMap::iterator findIt = m_postures->find(posture); + if (findIt == m_postures->end()) + { + slowMoveRateScale = 0.0f; + fastMoveRateScale = 0.0f; + accelerationScale = 0.0f; + turnScale = 0.0f; + + DEBUG_WARNING(true, ("MovementTable::getSlowAndFastMoveRates(): failed to find rate table entry for posture id=[%i],name=[%s], will return 0 rate.", posture, Postures::getPostureName(posture))); + return; + } + + const rates &rate = findIt->second; + + //-- Retrieve accel/turn rate modifiers. + accelerationScale = rate.accel; + turnScale = rate.turn; + + //-- Apply posture's movement rate. + slowMoveRateScale = (rate.slow != Locomotions::Invalid) ? rate.move : 0.0f; + fastMoveRateScale = (rate.fast != Locomotions::Invalid) ? rate.move : 0.0f; + + //-- Check if a state's max speed causes us to stop moving. + eLocomotionSpeed slowSpeed = kSlow; + eLocomotionSpeed fastSpeed = kFast; + + adjustTwoSpeedsForStates(states, slowSpeed, fastSpeed); + + slowMoveRateScale *= (slowSpeed >= kSlow) ? 1.0f : 0.0f; + fastMoveRateScale *= (fastSpeed >= kFast) ? 1.0f : 0.0f; + + //-- Retrieve and apply state movement rate modifiers. + float const stateRateModifier = getMovementRateModifierForStates(states); + + slowMoveRateScale *= stateRateModifier; + fastMoveRateScale *= stateRateModifier; +} + +// ---------------------------------------------------------------------- + +float MovementTable::getCanSeeHeightMod(Postures::Enumerator i_posture, uint64 i_states) const +{ + UNREF(i_states); + + if (i_posture < 0 || i_posture >= Postures::NumberOfPostures) + return 1.0f; + + const rates &rate = m_postures->find(i_posture)->second; + + return rate.canSeeHeightMod; +} + +// ---------------------------------------------------------------------- + +float MovementTable::getMovementRateModifierForStates(uint64 stateFlags) const +{ + DEBUG_FATAL(!ms_installed, ("MovementTable not installed.")); + + //-- Start with base rate modifier of multiplicative identity. + float rateModifier = 1.0f; + + if (stateFlags) + { + //-- Apply each state, one at a time. + for (States::Enumerator i = 0; i < States::NumberOfStates; ++i) + { + // Check if this state is present. + if (hasState(stateFlags, i)) + { + // Check if we have an entry for this state. + StateFloatMap::iterator const findIt = s_stateMovementRateModifiers.find(i); + if (findIt != s_stateMovementRateModifiers.end()) + { + // This state is present and we have a movement rate modifier for it. Apply the movement rate modifier. + rateModifier *= findIt->second; + } + } + } + } + + return rateModifier; +} + +// ====================================================================== +// class MovementTable: PRIVATE +// ====================================================================== + +MovementTable::eLocomotionSpeed MovementTable::adjustSpeedForStates(eLocomotionSpeed i_speed, uint64 i_states) const +{ + if (i_states) + for (States::Enumerator i = 0; i < States::NumberOfStates; ++i) + if (hasState(i_states, i) && ms_stateMoveLimit[i] < i_speed) + i_speed = ms_stateMoveLimit[i]; + return i_speed; +} + +// ---------------------------------------------------------------------- + +void MovementTable::adjustTwoSpeedsForStates(uint64 states, eLocomotionSpeed &speed1, eLocomotionSpeed &speed2) const +{ + if (states) + { + for (States::Enumerator i = 0; i < States::NumberOfStates; ++i) + { + if (hasState(states, i)) + { + eLocomotionSpeed const maxSpeed = ms_stateMoveLimit[i]; + if (speed1 > maxSpeed) + speed1 = maxSpeed; + + if (speed2 > maxSpeed) + speed2 = maxSpeed; + } + } + } +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/movement/MovementTable.h b/engine/shared/library/sharedObject/src/shared/movement/MovementTable.h new file mode 100644 index 00000000..e0076c2c --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/movement/MovementTable.h @@ -0,0 +1,87 @@ +// ====================================================================== +// +// MovementTable.h +// Copyright 2002-2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_MovementTable_H +#define INCLUDED_MovementTable_H + +//=================================================================== + +#include "swgSharedUtility/Locomotions.def" +#include "swgSharedUtility/Postures.def" +#include "swgSharedUtility/States.def" + +//=================================================================== + +class MovementTable +{ +public: + + enum eLocomotionSpeed + { + kInvalid = -1, + kStationary, + kSlow, + kFast + }; + +public: + + static void install(const std::string &stateFileName); + +public: + + MovementTable (const std::string &fileName, const std::string &templateName); // templateName is used for error messages + virtual ~MovementTable (); + + eLocomotionSpeed getLocomotionData(Locomotions::Enumerator locomotion, Postures::Enumerator &o_posture) const; + eLocomotionSpeed getPostureSpeed(Postures::Enumerator o_posture, Locomotions::Enumerator locomotion) const; + + Locomotions::Enumerator getLocomotion(Postures::Enumerator i_posture, uint64 i_states, eLocomotionSpeed speed) const; + void getAllLocomotions(Postures::Enumerator i_posture, uint64 i_states, Locomotions::Enumerator &fastLocomotion, Locomotions::Enumerator &slowLocomotion, Locomotions::Enumerator &stationaryLocomotion) const; + + bool getRates(Postures::Enumerator i_posture, float &moveScale, float &accelScale, float &turnScale) const; + bool hasMovingLocomotion(Postures::Enumerator i_posture, uint64 i_states) const; + + float getSlowMoveRate(Postures::Enumerator i_posture, uint64 i_states) const; + float getFastMoveRate(Postures::Enumerator i_posture, uint64 i_states) const; + void getAllMovementRateScales(Postures::Enumerator posture, uint64 states, float &slowMoveRateScale, float &fastMoveRateScale, float &accelerationScale, float &turnScale) const; + + float getCanSeeHeightMod(Postures::Enumerator i_posture, uint64 i_states) const; + + float getMovementRateModifierForStates(uint64 stateFlags) const; + +private: + + struct rates; + typedef stdmap::fwd PostureMap; + +private: + + eLocomotionSpeed adjustSpeedForStates(eLocomotionSpeed i_speed, uint64 i_states) const; + void adjustTwoSpeedsForStates(uint64 states, eLocomotionSpeed &speed1, eLocomotionSpeed &speed2) const; + + // Disabled. + MovementTable(); + MovementTable(const MovementTable&); + MovementTable& operator=(const MovementTable&); + +private: + + static bool ms_installed; + static eLocomotionSpeed ms_stateMoveLimit[States::NumberOfStates]; + +private: + + PostureMap* const m_postures; + Postures::Enumerator m_locomotionPostures[Locomotions::NumberOfLocomotions]; + +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/AlterResult.cpp b/engine/shared/library/sharedObject/src/shared/object/AlterResult.cpp new file mode 100644 index 00000000..2a7aab9c --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/AlterResult.cpp @@ -0,0 +1,53 @@ +// ====================================================================== +// +// AlterResult.cpp +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/AlterResult.h" + +#include +#include + +// ====================================================================== +/* + Note these constants are organized so that an object can return the + minimum value of all of its subcomponents/children and basically do + the right thing. If any subcomponent wants to be altered next frame, + the min of alter return values will be cms_alterNextFrame. If + no subcomponents care to be altered but at least one still wants to + live and specifies cms_keepNoAlter, then the object will return + cms_keepNoAlter. Finally, if all subcomponents want to be killed, + the object will return cms_kill. + + With the above in mind: DON'T CHANGE THESE VALUES (unless you think this + through and chek all the code that handles alter return values). +*/ + +float const AlterResult::cms_alterNextFrame = 0.0f; +float const AlterResult::cms_alterQuickly = 0.5f; +float const AlterResult::cms_keepNoAlter = 3.3e38f; +float const AlterResult::cms_kill = 3.4e38f; + +// ====================================================================== + +void AlterResult::formatTime(char *buffer, int bufferLength, float time) +{ + DEBUG_FATAL(bufferLength < 6, ("buffer length must be at least 5")); + + if (time == cms_alterNextFrame) + strcpy(buffer, "next "); + else + if (time == cms_keepNoAlter) + strcpy(buffer, "none "); + else + if (time == cms_kill) + strcpy(buffer, "kill "); + else + snprintf(buffer, bufferLength, "%5.2f", time); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/AlterResult.h b/engine/shared/library/sharedObject/src/shared/object/AlterResult.h new file mode 100644 index 00000000..b0ca9188 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/AlterResult.h @@ -0,0 +1,145 @@ +// ====================================================================== +// +// AlterResult.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_AlterResult_H +#define INCLUDED_AlterResult_H + +// ====================================================================== + +class AlterResult +{ +public: + + static void incorporateAlterResult(float &aggregateAlterResult, float componentAlterResult); + static void incorporateLongAlterResult(float &aggregateAlterResult, float componentAlterResult); + static void incorporateExactAlterResult(float &aggregateAlterResult, float componentAlterResult); + static void formatTime(char *buffer, int bufferLength, float time); + +public: + + static float const cms_alterQuickly; + static float const cms_alterNextFrame; + static float const cms_keepNoAlter; + static float const cms_kill; + +}; + +// ====================================================================== +/** + * Incorporate the alter result of a component into an aggregate alter result. + * + * This function takes care of some special cases, like ensuring that an aggregate + * return value of cms_kill does not get overwritten by another component that + * requests an alter some time in the future or requests to not be killed. + * + * If any component desires to be killed, the aggregate alter result will return + * cms_kill. + * + * @param aggregateAlterResult On input, contains the current aggregate alter result. + * This should be initialized by the caller to cms_keepNoAlter before + * incorporating the results of any component alter results. + * On output, contains the proper aggregate alter return value + * for the result. + * @param componentAlterResult The alter result of a component to incorporate. + */ +inline void AlterResult::incorporateAlterResult(float &aggregateAlterResult, float componentAlterResult) +{ + // If any component requests death, the aggregate will die. + if (componentAlterResult == AlterResult::cms_kill) //lint !e777 // testing float for equality // This is okay, we're using consts for set and test. + { + aggregateAlterResult = AlterResult::cms_kill; + } + else if (aggregateAlterResult != AlterResult::cms_kill) + { + //-- The next alter time for the object is the min next alter time specified. + // We must check to make sure that the aggregateAlterResult of "cms_kill" is not overwritten. + if (componentAlterResult < aggregateAlterResult) + { + aggregateAlterResult=componentAlterResult; + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Incorporate the alter result of a component into an aggregate alter result. This + * function differs from AlterResult::incorporateAlterResult() by insuring the largest + * alter time is used instead of the smallest. + * + * This function takes care of some special cases, like ensuring that an aggregate + * return value of cms_kill does not get overwritten by another component that + * requests an alter some time in the future or requests to not be killed. + * + * If any component desires to be killed, the aggregate alter result will return + * cms_kill. + * + * @param aggregateAlterResult On input, contains the current aggregate alter result. + * This should be initialized by the caller to cms_alterNextFrame before + * incorporating the results of any component alter results. + * On output, contains the proper aggregate alter return value + * for the result. + * @param componentAlterResult The alter result of a component to incorporate. + */ +inline void AlterResult::incorporateLongAlterResult(float &aggregateAlterResult, float componentAlterResult) +{ + // If any component requests death, the aggregate will die. + if (componentAlterResult == AlterResult::cms_kill) //lint !e777 // testing float for equality // This is okay, we're using consts for set and test. + { + aggregateAlterResult = AlterResult::cms_kill; + } + else if (aggregateAlterResult != AlterResult::cms_kill) + { + //-- The next alter time for the object is the max next alter time specified. + // We must check to make sure that the aggregateAlterResult of "cms_kill" is not overwritten. + if (componentAlterResult > aggregateAlterResult) + { + aggregateAlterResult=componentAlterResult; + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Incorporate the alter result of a component into an aggregate alter result. This + * function differs from AlterResult::incorporateAlterResult() by insuring that the + * componentAlterResult will always replace the aggregateAlterResult unless the object + * is to be killed. + * + * This function takes care of some special cases, like ensuring that an aggregate + * return value of cms_kill does not get overwritten by another component that + * requests an alter some time in the future or requests to not be killed. + * + * If any component desires to be killed, the aggregate alter result will return + * cms_kill. + * + * @param aggregateAlterResult On input, contains the current aggregate alter result. + * On output, contains the proper aggregate alter return value + * for the result. + * @param componentAlterResult The alter result of a component to incorporate. + */ +inline void AlterResult::incorporateExactAlterResult(float &aggregateAlterResult, float componentAlterResult) +{ + // If any component requests death, the aggregate will die. + if (componentAlterResult == AlterResult::cms_kill) //lint !e777 // testing float for equality // This is okay, we're using consts for set and test. + { + aggregateAlterResult = AlterResult::cms_kill; + } + else if (aggregateAlterResult != AlterResult::cms_kill) + { + //-- The next alter time for the object is the next alter time specified. + // We must check to make sure that the aggregateAlterResult of "cms_kill" is not overwritten. + aggregateAlterResult=componentAlterResult; + } +} + + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp b/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp new file mode 100644 index 00000000..f9d7e7dd --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp @@ -0,0 +1,1435 @@ +// ====================================================================== +// +// AlterScheduler.cpp +// Copyright 2002-2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/AlterScheduler.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/Object.h" +#include "sharedSynchronization/Mutex.h" + +#include +#include +#include +#include +#include +#include +#include + +#if _MSC_VER < 1300 +using std::type_info; +#endif + +// ====================================================================== + +#ifdef _DEBUG + // Set this flag to 1 to do additional (slow) error checking. +# define VALIDATE_OBJECTS 1 +# define USE_TYPEINFO_CATCH_BLOCK 1 +# define DO_RECURSION_CHECK 1 +# define DO_ON_DEBUG(op) op +#else +# define VALIDATE_OBJECTS 1 +# define USE_TYPEINFO_CATCH_BLOCK 1 +# define DO_RECURSION_CHECK 0 +# define DO_ON_DEBUG(op) NOP +#endif + +#define OBJECT_SCHEDULE_TIME_MAP_ITERATOR(objectReference) \ + *(static_cast((objectReference).getScheduleTimeMapIterator())) + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION +# define DO_ON_HARDCORE_VALIDATION(op) op +#else +# define DO_ON_HARDCORE_VALIDATION(op) NOP +#endif + +#if VALIDATE_OBJECTS +# define DO_ON_VALIDATE_OBJECTS(op) op +#else +# define DO_ON_VALIDATE_OBJECTS(op) NOP +#endif + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG +# define DO_ON_OBJECT_ALTER_FLAG_SUPPORTED(op) op +#else +# define DO_ON_OBJECT_ALTER_FLAG_SUPPORTED(op) NOP +#endif + +// ====================================================================== + +namespace AlterSchedulerNamespace +{ + typedef AlterScheduler::ScheduleTime ScheduleTime; + typedef AlterScheduler::ScheduleTimeMap ScheduleTimeMap; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class ObjectInfo + { + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + + public: + + explicit ObjectInfo(Object &object); + ~ObjectInfo(); + + Object const *getObject() const; + char const *getNetworkIdString() const; + char const *getObjectTemplateName() const; + + private: + + // Disabled. + ObjectInfo(); + + private: + + Object *m_object; + char *m_networkIdString; + char *m_objectTemplateName; + + }; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::map ObjectInfoMap; + typedef std::set ObjectSet; + typedef std::list ObjectList; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + float const cs_schedulerTicksPerSecond = 1000.0f; // # schedule ticks per second. Frame rates will not be able to exceed this. + float const cs_secondsPerSchedulerTick = 1.0f / cs_schedulerTicksPerSecond; + + uint32 const cs_freeFillPattern = 0xEFEFEFEF; // this should match MemoryManager's free fill pattern. + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + // Sentinel/guard nodes for first entry in these two lists. + Object *s_alterNextFrameListFirst[AS_MAX_SCHEDULE_PHASE_COUNT]; + Object *s_alterNowListFirst; + Object *s_concludeListFirst; + bool s_areListsValid; + + ScheduleTime s_currentTime; + float s_schedulerElapsedTime; + int s_objectsAltered; + int s_objectsNotAltered; + bool s_report; + bool s_suspendExecution; + bool s_alwaysAlter; + + bool s_trackObjectInfo; + ObjectInfoMap s_objectInfoMap; + +#if DO_RECURSION_CHECK + Mutex *s_criticalSection; + int s_recursionDepth; +#endif + +#ifdef _DEBUG + bool s_logAddRemove; + bool s_reportPerObject; + bool s_profileAlterByType; + Object const * s_currentlyAlteringObject; + int s_totalObjectAlterCalls; + int s_reportedObjectAlterCalls; + char const * s_reportedAppearanceType; + float s_reportedAppearanceResult; + char const * s_reportedControllerType; + float s_reportedControllerResult; + char const * s_reportedDynamicsType; + float s_reportedDynamicsResult; + float s_reportedChildrenResult; + float s_reportedObjectResult; +#endif + + char s_crashReportInfo[MAX_PATH * 2]; + + + ScheduleTimeMap s_scheduleMap; // Sorted by next alter time for efficient scheduling. + + AlterScheduler::PostAlterHookFunction s_postAlterHookFunction; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void remove(); + void reportPrint(); + void validateObject(Object const* object); + void addObjectInfoAsNecessary(Object &object); + +#ifdef _DEBUG + void doPerObjectAlterReportCollection(Object const* object, float alterResult); +#endif + +#if DO_RECURSION_CHECK + void incrementRecursionDepth(); + void decrementRecursionDepth(); + int getRecursionDepth(); + + void doPreAlterRecursionCheck(); + void doPostAlterRecursionCheck(); +#else + #define doPreAlterRecursionCheck() NOP + #define doPostAlterRecursionCheck() NOP +#endif + + void incrementSchedulerTimerByElapsedTime(float schedulerElapsedTime); +} + +using namespace AlterSchedulerNamespace; + +// ====================================================================== +// class AlterSchedulerNamespace::ObjectInfo +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(AlterSchedulerNamespace::ObjectInfo, true, 0, 0, 0); + +// ====================================================================== + +AlterSchedulerNamespace::ObjectInfo::ObjectInfo(Object &object): + m_object(&object), + m_networkIdString(DuplicateString(object.getNetworkId().getValueString().c_str())), + m_objectTemplateName(DuplicateString(object.getObjectTemplateName())) +{ +} + +// ---------------------------------------------------------------------- + +AlterSchedulerNamespace::ObjectInfo::~ObjectInfo() +{ + delete [] m_objectTemplateName; + delete [] m_networkIdString; + m_object = 0; +} + +// ---------------------------------------------------------------------- + +Object const *AlterSchedulerNamespace::ObjectInfo::getObject() const +{ + return m_object; +} + +// ---------------------------------------------------------------------- + +char const *AlterSchedulerNamespace::ObjectInfo::getNetworkIdString() const +{ + return m_networkIdString; +} + +// ---------------------------------------------------------------------- + +char const *AlterSchedulerNamespace::ObjectInfo::getObjectTemplateName() const +{ + return m_objectTemplateName; +} + +// ====================================================================== +// Namespace AlterSchedulerNamespace functions +// ====================================================================== + +void AlterSchedulerNamespace::remove() +{ + CrashReportInformation::removeDynamicText(s_crashReportInfo); + + s_areListsValid = false; + + for (int i = 0; i < AS_MAX_SCHEDULE_PHASE_COUNT; ++i) + delete s_alterNextFrameListFirst[i]; + + delete s_alterNowListFirst; + delete s_concludeListFirst; + +#if DO_RECURSION_CHECK + delete s_criticalSection; + s_criticalSection = 0; +#endif + + ObjectInfoMap::iterator const endIt = s_objectInfoMap.end(); + for (ObjectInfoMap::iterator it = s_objectInfoMap.begin(); it != endIt; ++it) + delete it->second; + + s_objectInfoMap.clear(); +} + +// ---------------------------------------------------------------------- + +void AlterSchedulerNamespace::reportPrint() +{ + DEBUG_REPORT_PRINT(true, ("AlterScheduler: elapsed time: [%.3f]\n", s_schedulerElapsedTime)); + DEBUG_REPORT_PRINT(true, ("AlterScheduler: internal time: [%d].\n", static_cast(s_currentTime))); + DEBUG_REPORT_PRINT(true, ("AlterScheduler: scheduler map entry count: [%d].\n", static_cast(s_scheduleMap.size()))); + DEBUG_REPORT_PRINT(true, ("AlterScheduler: most recent frame alter count: [%d].\n", s_objectsAltered)); +} + +// ---------------------------------------------------------------------- +/** + * NULL objects are not considered valid by this function. Do not call this on a NULL + * object if that happens to be valid in the context in which this function is used. + */ + +void AlterSchedulerNamespace::validateObject(Object const *object) +{ + FATAL(!object, ("validateObject(): alter scheduler found NULL object.")); + + DO_ON_VALIDATE_OBJECTS(bool isInvalid = false); + +#if VALIDATE_OBJECTS + +#ifdef _DEBUG + //-- Check if object memory is deleted. + if (*reinterpret_cast(object) == cs_freeFillPattern) //lint !e740 // unusual pointer cast // Yes. + { + DEBUG_WARNING(true, ("validateObject(): alter scheduler found deleted object (object memory starts with 4 bytes of free-fill pattern).")); //lint !e740 // unusual pointer cast from incompatible indirect types // okay, I'm doing something unusual. + isInvalid = true; + } +#endif // _DEBUG + +#if USE_TYPEINFO_CATCH_BLOCK + if (!isInvalid) + { + try + { +#endif + + // If you crash here, object is an invalid pointer and should not be handled by the alter scheduler. + type_info const &typeInfo = typeid(*object); + UNREF(typeInfo); + +#if USE_TYPEINFO_CATCH_BLOCK + } + catch (...) + { //lint !e1775 // catch block does not declare any exception // that's right: I want to catch it all. + WARNING(true, ("validateObject(): Object-derived class with address [%x] failed to return valid C++ type info; likely a deleted Object.", reinterpret_cast(object))); + isInvalid = true; + } + } +#endif + +#if OBJECT_SUPPORTS_DESTROYED_FLAG + //-- Check if specified object is already destroyed. + if (!isInvalid && object->isDestroyed()) + { + WARNING(true, ("validateObject(): alter scheduler found destroyed object, pointer=[%p].", object)); + isInvalid = true; + } +#endif // OBJECT_SUPPORTS_DESTROYED_FLAG + + if (isInvalid) + { + //-- Print out object info for the invalid object if we have it. + ObjectInfo *objectInfo = NULL; + if (s_trackObjectInfo) + { + ObjectInfoMap::iterator findIt = s_objectInfoMap.find(const_cast(object)); + if (findIt != s_objectInfoMap.end()) + objectInfo = findIt->second; + } + + if (objectInfo) + FATAL(true, ("We tracked object info for pointer=[%p]: object id=[%s], object template=[%s].", object, objectInfo->getNetworkIdString(), objectInfo->getObjectTemplateName())); + else + FATAL(true, ("We either don't track object info or we had no object info for object pointer=[%p].", object)); + } + +#endif // VALIDATE_OBJECTS + + UNREF(object); +} + +// ---------------------------------------------------------------------- +/** + * Return true if two strings are the same (or are both NULL); otherwise, return false. + */ + +static bool SafeStringEqual(char const *string1, char const *string2) +{ + if (string1 && string2) + return (strcmp(string1, string2) == 0); + else if (!string1 && !string2) + return true; + else + return false; +} + +// ---------------------------------------------------------------------- + +void AlterSchedulerNamespace::addObjectInfoAsNecessary(Object &object) +{ + DEBUG_FATAL(!s_trackObjectInfo, ("addObjectInfoAsNecessary(): Shouldn't be calling this function, object info tracking is disabled.")); + + //-- Check if we have an entry for this object. + ObjectInfoMap::iterator findIt = s_objectInfoMap.find(&object); + if (findIt == s_objectInfoMap.end()) + { + //-- Doesn't exist. Add now. + IGNORE_RETURN(s_objectInfoMap.insert(ObjectInfoMap::value_type(&object, new ObjectInfo(object)))); + } + else + { + //-- Verify that they're the same. If not, object pointer has been reused, create new object info. + ObjectInfo *const existingInfo = findIt->second; + NOT_NULL(existingInfo); + + bool replace = false; + if (!SafeStringEqual(existingInfo->getNetworkIdString(), object.getNetworkId().getValueString().c_str())) + { + DEBUG_REPORT_LOG(true, ("AlterSchedulerNamespace::addObjectInfoAsNecessary(): Object pointer [%p] has new network id, old=[%s],new=[%s], Object pointer probably reused.\n", &object, existingInfo->getNetworkIdString(), object.getNetworkId().getValueString().c_str())); + replace = true; + } + + if (!SafeStringEqual(existingInfo->getObjectTemplateName(), object.getObjectTemplateName())) + { + DEBUG_REPORT_LOG(true, ("AlterSchedulerNamespace::addObjectInfoAsNecessary(): Object pointer [%p] has new object template name, old=[%s],new=[%s], Object pointer probably reused.\n", &object, existingInfo->getObjectTemplateName(), object.getObjectTemplateName())); + replace = true; + } + + if (replace) + { + delete existingInfo; + findIt->second = new ObjectInfo(object); + } + } +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void AlterSchedulerNamespace::doPerObjectAlterReportCollection(Object const* object, float alterResult) +{ + if (s_reportPerObject) + { + char appearanceAlterResultText[16]; + char controllerAlterResultText[16]; + char dynamicsAlterResultText[16]; + char childrenAlterResultText[16]; + char objectAlterResultText[16]; + char finalAlterResultText[16]; + + char const * debugName = "deleted"; + char const * objectTemplateName = ""; + + debugName = object->getDebugName(); + if (!debugName) + debugName = "unknown"; + objectTemplateName = object->getObjectTemplateName(); + if (!objectTemplateName) + objectTemplateName = "unknown"; + + AlterResult::formatTime(appearanceAlterResultText, sizeof(appearanceAlterResultText), s_reportedAppearanceResult); + AlterResult::formatTime(controllerAlterResultText, sizeof(controllerAlterResultText), s_reportedControllerResult); + AlterResult::formatTime(dynamicsAlterResultText, sizeof(dynamicsAlterResultText), s_reportedDynamicsResult); + AlterResult::formatTime(childrenAlterResultText, sizeof(childrenAlterResultText), s_reportedChildrenResult); + AlterResult::formatTime(objectAlterResultText, sizeof(objectAlterResultText), s_reportedObjectResult); + AlterResult::formatTime(finalAlterResultText, sizeof(finalAlterResultText), alterResult); + DEBUG_REPORT_PRINT(true, ("object %s %s\n %d calls to Object::alter\n %s %s appearance\n %s %s controller\n %s %s dynamics\n %s children\n %s object\n %s final\n", debugName, objectTemplateName, s_totalObjectAlterCalls, appearanceAlterResultText, s_reportedAppearanceType, controllerAlterResultText, s_reportedControllerType, dynamicsAlterResultText, s_reportedDynamicsType, childrenAlterResultText, objectAlterResultText, finalAlterResultText)); + } +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_RECURSION_CHECK + +void AlterSchedulerNamespace::incrementRecursionDepth() +{ + NOT_NULL(s_criticalSection); + + s_criticalSection->enter(); + { + ++s_recursionDepth; + } + s_criticalSection->leave(); +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_RECURSION_CHECK + +void AlterSchedulerNamespace::decrementRecursionDepth() +{ + NOT_NULL(s_criticalSection); + + s_criticalSection->enter(); + { + --s_recursionDepth; + DEBUG_FATAL(s_recursionDepth < 0, ("invalid recursion depth < 0 [%d].", s_recursionDepth)); + } + s_criticalSection->leave(); +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_RECURSION_CHECK + +int AlterSchedulerNamespace::getRecursionDepth() +{ + NOT_NULL(s_criticalSection); + + int value; + s_criticalSection->enter(); + { + value = s_recursionDepth; + } + s_criticalSection->leave(); + + return value; +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_RECURSION_CHECK + +void AlterSchedulerNamespace::doPreAlterRecursionCheck() +{ + //-- Check for recursive calling on the front end. + incrementRecursionDepth(); + FATAL(getRecursionDepth() > 1, ("Recursively calling AlterSchedulerNamespace::doAlterConclude(), this must be fixed.")); +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_RECURSION_CHECK + +void AlterSchedulerNamespace::doPostAlterRecursionCheck() +{ + //-- Check for recursive calling on the back end. + decrementRecursionDepth(); + FATAL(getRecursionDepth() > 0, ("AlterSchedulerNamespace::doAlterConclude() called recursively, must fix.")); +} + +#endif + +// ---------------------------------------------------------------------- + +void AlterSchedulerNamespace::incrementSchedulerTimerByElapsedTime(float schedulerElapsedTime) +{ + // Compute new absolute scheduler time. + s_schedulerElapsedTime = schedulerElapsedTime; + + ScheduleTime const previousSchedulerTime = s_currentTime; + s_currentTime += static_cast(schedulerElapsedTime * cs_schedulerTicksPerSecond); + + if (previousSchedulerTime == s_currentTime) + { + //-- If this warning/fatal is hit, check the following: + // * Did something call AlterScheduler::alter() with zero time? That should not happen. + // * Is the ticks per second float-to-integral conversion factor too small? If so, fast framerates can cause this variable to stay zero. + // Fixes for this are to increase the # ticks per second (may require changing ScheduleTime from 32 bits to 64 bits). + WARNING_STRICT_FATAL(true, ("doAlterConclude() called with elapsed time [%g] resulting in no forward time movement, bumping up elapsed time to [%g].", schedulerElapsedTime, cs_secondsPerSchedulerTick)); + ++s_currentTime; + } +} + +// ====================================================================== +// class AlterScheduler: PUBLIC STATIC +// ====================================================================== + +void AlterScheduler::install() +{ + DebugFlags::registerFlag(s_report, "SharedObject/AlterScheduler", "report", reportPrint); + DebugFlags::registerFlag(s_suspendExecution, "SharedObject/AlterScheduler", "suspendExecution"); + DebugFlags::registerFlag(s_alwaysAlter, "SharedObject/AlterScheduler", "alwaysAlter"); + DebugFlags::registerFlag(s_trackObjectInfo, "SharedObject/AlterScheduler", "trackObjectInfo"); + + ObjectInfo::install(); + + for (int i = 0; i < AS_MAX_SCHEDULE_PHASE_COUNT; ++i) + { + s_alterNextFrameListFirst[i] = new Object; + s_alterNextFrameListFirst[i]->createScheduleDataIfNecessary(s_currentTime); + } + + s_alterNowListFirst = new Object; + s_alterNowListFirst->createScheduleDataIfNecessary(s_currentTime); + + s_concludeListFirst = new Object; + s_concludeListFirst->createScheduleDataIfNecessary(s_currentTime); + + s_areListsValid = true; + +#if DO_RECURSION_CHECK + s_criticalSection = new Mutex(); +#endif + + s_crashReportInfo[0] = '\0'; + CrashReportInformation::addDynamicText(s_crashReportInfo); + + DO_ON_DEBUG( DebugFlags::registerFlag(s_reportPerObject, "SharedObject/AlterScheduler", "reportPerObject") ); + DO_ON_DEBUG( DebugFlags::registerFlag(s_profileAlterByType, "SharedObject/AlterScheduler", "profileAlterByType") ); + DO_ON_DEBUG( DebugFlags::registerFlag(s_logAddRemove, "SharedObject/AlterScheduler", "logAddRemove") ); + + ExitChain::add(remove, "AlterScheduler"); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::submitForAlter(Object &object) +{ + if (!object.getUseAlterScheduler()) + return; + + DEBUG_REPORT_LOG(s_logAddRemove, ("AlterScheduler::submitForAlter: object pointer=[%p], id=[%s], template=[%s]\n", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); + DO_ON_VALIDATE_OBJECTS(validateObject(&object)); + + if (s_trackObjectInfo) + addObjectInfoAsNecessary(object); + + DEBUG_FATAL(!object.isInitialized(), ("AlterScheduler::submitForAlter(): tried to add an uninitialized object to alter scheduler, call site must fix. Pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); + + //-- If this is the first time this Object is getting scheduled, create the + // per-Object ScheduleData and initialize the most recent alter time to the specified value. + object.createScheduleDataIfNecessary(s_currentTime); + addToAlterNextFrameList(object); +} + +// ---------------------------------------------------------------------- +/** + * @return true if the object existed in the alter scheduler, false otherwise. + */ + +bool AlterScheduler::removeObject(Object &object) +{ + DO_ON_OBJECT_ALTER_FLAG_SUPPORTED( DEBUG_FATAL(object.isAltering(), ("AlterScheduler::removeObject(): unsupported: tried to remove object from alter scheduler during alter. Pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())) ); + + DEBUG_REPORT_LOG(s_logAddRemove, ("AlterScheduler::removeObject: object pointer=[%p], id=[%s], template=[%s]\n", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())); + + if (!object.hasScheduleData()) + return false; + + bool result = false; + + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::removeObject"); + + //-- Remove object from each of the alter scheduler lists. + if (object.isInAlterNowList()) + { + object.removeFromAlterNowList(); + result = true; + } + + if (object.isInAlterNextFrameList()) + { + object.removeFromAlterNextFrameList(); + result = true; + } + + if (object.isInConcludeList()) + { + object.removeFromConcludeList(); + result = true; + } + + ScheduleTimeMap::iterator &mapIt = OBJECT_SCHEDULE_TIME_MAP_ITERATOR(object); + if (mapIt != s_scheduleMap.end()) + { + s_scheduleMap.erase(mapIt); + mapIt = s_scheduleMap.end(); + result = true; + } + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(AlterScheduler::findObjectInScheduleTimeMap(&object), ("removeObject(): object shouldn't be in map but is: pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())) ); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + if (s_areListsValid) + { + uint32 const findResult = findObject(&object); + FATAL(findResult > 0, ("object pointer=[%p], id=[%s], template=[%s] should not be accessible but is [%d], alter scheduler corruption, TRF bug.", + &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName(), findResult)); + } +#endif + + return result; +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::setObjectSchedulePhase(Object &object, int schedulePhaseIndex) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, schedulePhaseIndex, AS_MAX_SCHEDULE_PHASE_COUNT); + + object.createScheduleDataIfNecessary(s_currentTime); + object.setAlterSchedulePhase(schedulePhaseIndex); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::alter(float elapsedTime) +{ + DO_ON_DEBUG(if (s_suspendExecution) return); + + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::alter"); + doAlterAndConcludeForAllObjects(elapsedTime, CS_none, NULL); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::alterAllAndConcludeOne(float elapsedTime, Object * objectToConclude) +{ + DO_ON_DEBUG(if (s_suspendExecution) return); + + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::alterAndConclude"); + doAlterAndConcludeForAllObjects(elapsedTime, CS_one, objectToConclude); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::alterAndConclude(float elapsedTime) +{ + DO_ON_DEBUG(if (s_suspendExecution) return); + + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::alterAndConclude"); + doAlterAndConcludeForAllObjects(elapsedTime, CS_all, NULL); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::setPostAlterHookFunction (PostAlterHookFunction postAlterHookFunction) +{ + s_postAlterHookFunction = postAlterHookFunction; +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::initializeScheduleTimeMapIterator(Object &object) +{ + // Set iterator value contained in pointer to the end of the schedule time map. + OBJECT_SCHEDULE_TIME_MAP_ITERATOR(object) = s_scheduleMap.end(); +} + +// ---------------------------------------------------------------------- + +bool AlterScheduler::isIteratorInScheduleTimeMap(void const *iterator) +{ + DEBUG_FATAL(!iterator, ("AlterScheduler::isIteratorInScheduleTimeMap(): iterator pointer is NULL.")); + return (*static_cast(iterator) != s_scheduleMap.end()); +} + +// ---------------------------------------------------------------------- + +bool AlterScheduler::findObjectInAlterNowList(Object const *object) +{ + DO_ON_HARDCORE_VALIDATION(validateAlterNowList()); + + for (Object *searchObject = s_alterNowListFirst->getNextFromAlterNowList(); searchObject != NULL; searchObject = searchObject->getNextFromAlterNowList()) + { + if (searchObject == object) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool AlterScheduler::findObjectInAlterNextFrameLists(Object const *object) +{ + DO_ON_HARDCORE_VALIDATION(validateAlterNextFrameList()); + + for (int phaseIndex = 0; phaseIndex < AS_MAX_SCHEDULE_PHASE_COUNT; ++phaseIndex) + { + for (Object *searchObject = s_alterNextFrameListFirst[phaseIndex]->getNextFromAlterNextFrameList(); searchObject != NULL; searchObject = searchObject->getNextFromAlterNextFrameList()) + { + if (searchObject == object) + return true; + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool AlterScheduler::findObjectInConcludeList(Object const *object) +{ + DO_ON_HARDCORE_VALIDATION(validateConcludeList()); + + for (Object *searchObject = s_concludeListFirst->getNextFromConcludeList(); searchObject != NULL; searchObject = searchObject->getNextFromConcludeList()) + { + if (searchObject == object) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool AlterScheduler::findObjectInScheduleTimeMap(Object const *object) +{ + DO_ON_HARDCORE_VALIDATION(validateScheduleTimeMap()); + + ScheduleTimeMap::iterator const endIt = s_scheduleMap.end(); + for (ScheduleTimeMap::iterator it = s_scheduleMap.begin(); it != endIt; ++it) + if (it->second == object) + return true; + + return false; +} + +// ---------------------------------------------------------------------- + +uint32 AlterScheduler::findObject(Object const *object) +{ + uint32 result = 0; + + if (findObjectInAlterNowList(object)) + result |= 0x01; + + if (findObjectInAlterNextFrameLists(object)) + result |= 0x02; + + if (findObjectInScheduleTimeMap(object)) + result |= 0x04; + + return result; +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::validateAlterNowList() +{ + ObjectSet objectSet; + ObjectList objectList; + + //-- Add each object to the set and list. + { + for (Object *object = s_alterNowListFirst->getNextFromAlterNowList(); object != NULL; object = object->getNextFromAlterNowList()) + { + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + // Insert into set, checking for multiple entries of same value. + std::pair result = objectSet.insert(object); + UNREF(result); + DEBUG_FATAL(!result.second, ("validateAlterNowList(): failed, object appears multiple times: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + + // Append to list. + objectList.push_back(object); + } + } + + //-- Walk list forward and make sure they match. + Object *lastObject = s_alterNowListFirst; + { + ObjectList::iterator const endIt = objectList.end(); + Object *object = s_alterNowListFirst->getNextFromAlterNowList(); + for (ObjectList::iterator it = objectList.begin(); (it != endIt) && (object != NULL); object = object->getNextFromAlterNowList(), ++it) + { + lastObject = object; + DEBUG_WARNING(object != *it, ("validateAlterNowList(): forward linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateAlterNowList(): forward linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } + + //-- Walk list backward and make sure they match. + { + ObjectList::reverse_iterator const endIt = objectList.rend(); + Object *object = lastObject; + for (ObjectList::reverse_iterator it = objectList.rbegin(); (it != endIt) && (object != NULL); object = object->getPreviousFromAlterNowList(), ++it) + { + DEBUG_WARNING(object != *it, ("validateAlterNowList(): reverse linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateAlterNowList(): reverse linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::validateAlterNextFrameLists() +{ + ObjectSet objectSet; + ObjectList objectList; + + for (int phaseIndex = 0; phaseIndex < AS_MAX_SCHEDULE_PHASE_COUNT; ++phaseIndex) + { + //-- Add each object to the set and list. + { + for (Object *object = s_alterNextFrameListFirst[phaseIndex]->getNextFromAlterNextFrameList(); object != NULL; object = object->getNextFromAlterNextFrameList()) + { + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + // Insert into set, checking for multiple entries of same value. + std::pair result = objectSet.insert(object); + UNREF(result); + DEBUG_FATAL(!result.second, ("validateAlterNextFrameList(): failed, object appears multiple times: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + + // Append to list. + objectList.push_back(object); + } + } + + //-- Walk list forward and make sure they match. + Object *lastObject = s_alterNextFrameListFirst[phaseIndex]; + { + ObjectList::iterator const endIt = objectList.end(); + Object *object = s_alterNextFrameListFirst[phaseIndex]->getNextFromAlterNextFrameList(); + for (ObjectList::iterator it = objectList.begin(); (it != endIt) && (object != NULL); object = object->getNextFromAlterNextFrameList(), ++it) + { + lastObject = object; + DEBUG_WARNING(object != *it, ("validateAlterNextFrameList(): forward linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateAlterNextFrameList(): forward linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } + + //-- Walk list backward and make sure they match. + { + ObjectList::reverse_iterator const endIt = objectList.rend(); + Object *object = lastObject; + for (ObjectList::reverse_iterator it = objectList.rbegin(); (it != endIt) && (object != NULL); object = object->getPreviousFromAlterNextFrameList(), ++it) + { + DEBUG_WARNING(object != *it, ("validateAlterNextFrameList(): reverse linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateAlterNextFrameList(): reverse linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } + + objectSet.clear(); + objectList.clear(); + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::validateConcludeList() +{ + ObjectSet objectSet; + ObjectList objectList; + + //-- Add each object to the set and list. + { + for (Object *object = s_concludeListFirst->getNextFromConcludeList(); object != NULL; object = object->getNextFromConcludeList()) + { + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + // Insert into set, checking for multiple entries of same value. + std::pair result = objectSet.insert(object); + UNREF(result); + DEBUG_FATAL(!result.second, ("validateConcludeList(): failed, object appears multiple times: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + + // Append to list. + objectList.push_back(object); + } + } + + //-- Walk list forward and make sure they match. + Object *lastObject = s_concludeListFirst; + { + ObjectList::iterator const endIt = objectList.end(); + Object *object = s_concludeListFirst->getNextFromConcludeList(); + for (ObjectList::iterator it = objectList.begin(); (it != endIt) && (object != NULL); object = object->getNextFromConcludeList(), ++it) + { + lastObject = object; + DEBUG_WARNING(object != *it, ("validateConcludeList(): forward linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateConcludeList(): forward linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } + + //-- Walk list backward and make sure they match. + { + ObjectList::reverse_iterator const endIt = objectList.rend(); + Object *object = lastObject; + for (ObjectList::reverse_iterator it = objectList.rbegin(); (it != endIt) && (object != NULL); object = object->getPreviousFromConcludeList(), ++it) + { + DEBUG_WARNING(object != *it, ("validateConcludeList(): reverse linkage check failed, stl list: pointer=[%p], object id=[%s], object template=[%s].", *it, (*it)->getNetworkId().getValueString().c_str(), (*it)->getObjectTemplateName())); + DEBUG_FATAL(object != *it, ("validateConcludeList(): reverse linkage check failed, alter scheduler list: pointer=[%p], object id=[%s], object template=[%s].", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::validateScheduleTimeMap() +{ + //-- Make sure each object is in this only once. + ObjectSet objectSet; + + int duplicateCount = 0; + + ScheduleTimeMap::iterator const endIt = s_scheduleMap.end(); + for (ScheduleTimeMap::iterator it = s_scheduleMap.begin(); it != endIt; ++it) + { + DO_ON_VALIDATE_OBJECTS(validateObject(it->second)); + + // Insert into set, checking for multiple entries of same value. + std::pair result = objectSet.insert(it->second); + if (!result.second) + { + DEBUG_WARNING(true, ("validateAlterScheduleTimeMap(): failed, object appears multiple times: pointer=[%p], object id=[%s], object template=[%s].", it->second, it->second->getNetworkId().getValueString().c_str(), it->second->getObjectTemplateName())); + ++duplicateCount; + } + } + + DEBUG_FATAL(duplicateCount > 0, ("validateScheduleTimeMap(): duplicates found, see warnings in output.")); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::validateAllContainers() +{ + validateAlterNowList(); + validateAlterNextFrameLists(); + validateConcludeList(); + validateScheduleTimeMap(); +} + +// ---------------------------------------------------------------------- + +float AlterScheduler::getTimeSinceLastFrame() +{ + return s_schedulerElapsedTime; +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::setMostRecentAlterTime(Object &object) +{ + if (object.hasScheduleData()) + object.setMostRecentAlterTime(s_currentTime); +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +bool AlterScheduler::reportObjectAlters() +{ + return s_reportPerObject; +} + +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void AlterScheduler::countObjectAlter() +{ + ++s_totalObjectAlterCalls; + ++s_reportedObjectAlterCalls; +} + +#endif + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG + +void AlterScheduler::reportObjectAlter(Object const * object, char const * appearanceType, float appearanceResult, char const * controllerType, float controllerResult, char const * dynamicsType, float dynamicsResult, float childrenResult, float objectResult) +{ + if (object == s_currentlyAlteringObject) + { + s_reportedAppearanceType = appearanceType; + s_reportedAppearanceResult = appearanceResult; + s_reportedControllerType = controllerType; + s_reportedControllerResult = controllerResult; + s_reportedDynamicsType = dynamicsType; + s_reportedDynamicsResult = dynamicsResult; + s_reportedChildrenResult = childrenResult; + s_reportedObjectResult = objectResult; + } +} + +#endif + +// ====================================================================== +// class AlterScheduler: PRIVATE STATIC +// ====================================================================== + +void AlterScheduler::addToAlterNextFrameList(Object &object) +{ + //-- Ensure it's not in the future schedule list. + // Note it's okay if it's in the alter now list since the object may + // get a submitForAlter() from a related object during alter processing. + ScheduleTimeMap::iterator &mapIt = OBJECT_SCHEDULE_TIME_MAP_ITERATOR(object); + if (mapIt != s_scheduleMap.end()) + { + s_scheduleMap.erase(mapIt); + mapIt = s_scheduleMap.end(); + } + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(AlterScheduler::findObjectInScheduleTimeMap(&object), ("addToAlterNextFrameList(): object shouldn't be in map but is: pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())) ); + + //-- Add to next frame list as necessary. + if (!object.isInAlterNextFrameList()) + { + int const schedulePhase = object.getAlterSchedulePhase(); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, schedulePhase, AS_MAX_SCHEDULE_PHASE_COUNT); + + object.insertIntoAlterNextFrameList(s_alterNextFrameListFirst[schedulePhase]); + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::addToAlterNowList(Object &object) +{ + //-- Remove from any other container. + if (object.isInAlterNextFrameList()) + object.removeFromAlterNextFrameList(); + + ScheduleTimeMap::iterator &mapIt = OBJECT_SCHEDULE_TIME_MAP_ITERATOR(object); + if (mapIt != s_scheduleMap.end()) + { + s_scheduleMap.erase(mapIt); + mapIt = s_scheduleMap.end(); + } + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(AlterScheduler::findObjectInScheduleTimeMap(&object), ("addToAlterNowList(): object shouldn't be in map but is: pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())) ); + + //-- Add to alter now list as necessary. + if (!object.isInAlterNowList()) + object.insertIntoAlterNowList(s_alterNowListFirst); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::addToScheduleMap(Object &object, ScheduleTime nextAlterTime) +{ + //-- Remove from alter next frame list. + if (object.isInAlterNextFrameList()) + object.removeFromAlterNextFrameList(); + + ScheduleTimeMap::iterator &mapIt = OBJECT_SCHEDULE_TIME_MAP_ITERATOR(object); + if (mapIt != s_scheduleMap.end()) + s_scheduleMap.erase(mapIt); + + //-- Add object to schedule map. + mapIt = s_scheduleMap.insert(ScheduleTimeMap::value_type(nextAlterTime, &object)); + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(!AlterScheduler::findObjectInScheduleTimeMap(&object), ("addToScheduleMap(): object should be in map but isn't: pointer=[%p],id=[%s],template=[%s].", &object, object.getNetworkId().getValueString().c_str(), object.getObjectTemplateName())) ); +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::dumpScheduleMap() +{ + REPORT_LOG(true, ("Dumping schedule map: %d entries.\n", static_cast(s_scheduleMap.size()))); + + ScheduleTimeMap::iterator const endIt = s_scheduleMap.end(); + int i = 0; + + for (ScheduleTimeMap::iterator it = s_scheduleMap.begin(); it != endIt; ++it, ++i) + { + Object *const object = it->second; + if (object) + { + ScheduleTime nextAlterTime = it->first; + REPORT_LOG(true, ("%d: object id [%s], ptr=[%p], last alter [%d], next alter [%d].\n", i+1, object->getNetworkId().getValueString().c_str(), object, static_cast(object->getMostRecentAlterTime()), static_cast(nextAlterTime))); + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::moveReadyObjectsFromSchedulerToNextFrameList() +{ + //-- Copy all expired alter scheduler entries into the "alter next frame" list. + { + PROFILER_AUTO_BLOCK_DEFINE("update expired"); + + while (!s_scheduleMap.empty()) + { + ScheduleTimeMap::iterator it = s_scheduleMap.begin(); + if (!s_alwaysAlter && (s_currentTime < it->first)) + { + //-- We're not always altering and we've hit an entry whose expiration time has not yet been hit. + // We're done searching for new entries to alter this frame. + break; + } + else + { + //-- Get object, validate it. + Object *const object = it->second; + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + //-- This function will remove the object from the schedule map. + addToAlterNextFrameList(*object); + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(findObjectInAlterNowList(object), ("found object in alter now list, unexpected.")) ); + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(findObjectInScheduleTimeMap(object), ("found object in time schedule map, unexpected.")) ); + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(!findObjectInAlterNextFrameList(object), ("didn't find object in alter next frame list, unexpected.")) ); + } + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::moveObjectsFromAlterNextFrameListToAlterNowList(int schedulePhaseIndex) +{ + //-- Copy all alter next frame entries into the alter now list. + s_objectsAltered = 0; + { + PROFILER_AUTO_BLOCK_DEFINE("copy next frame"); + + NOT_NULL(s_alterNextFrameListFirst); + for (Object *object = s_alterNextFrameListFirst[schedulePhaseIndex]->getNextFromAlterNextFrameList(); object != NULL; ) + { + //-- Add object to alter now list. This removes the object from the alter next frame list. + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + //-- Save next object in list. + Object *const nextObject = object->getNextFromAlterNextFrameList(); + + addToAlterNowList(*object); + ++s_objectsAltered; + + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(findObjectInScheduleTimeMap(object), ("found object in time schedule map, unexpected.")) ); + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(findObjectInAlterNextFrameList(object), ("found object in alter next frame list, unexpected.")) ); + DO_ON_HARDCORE_VALIDATION( DEBUG_FATAL(!findObjectInAlterNowList(object), ("didn't find object in alter now list, unexpected.")) ); + + //-- Increment loop. + object = nextObject; + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::alterSingleObject(Object *object, ConcludeStyle concludeStyle, Object *&nextObject) +{ + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + DO_ON_HARDCORE_VALIDATION(DEBUG_FATAL(!findObjectInAlterNowList(object), ("didn't find object in alter now list, unexpected."))); + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + + //-- Figure out how much time to apply to alter(). + float const elapsedTime = cs_secondsPerSchedulerTick * (s_currentTime - object->getMostRecentAlterTime()); + + DO_ON_DEBUG(s_reportedObjectAlterCalls = 0); + DO_ON_DEBUG(s_currentlyAlteringObject = object); + +#if defined(_WIN32) && defined(_DEBUG) + char const * const typeName = s_profileAlterByType ? typeid(*object).name() : NULL; + PROFILER_BLOCK_DEFINE(profilerBlock, typeName); + if (typeName) + PROFILER_BLOCK_ENTER(profilerBlock); +#endif + + float alterResult = AlterResult::cms_alterNextFrame; + bool alreadyProcessed = (object->getMostRecentAlterTime() == s_currentTime); + if (!alreadyProcessed) + { + //-- Update the most recent alter time for this object. + object->setMostRecentAlterTime(s_currentTime); + + //-- Perform the alter. + DO_ON_OBJECT_ALTER_FLAG_SUPPORTED(object->setIsAltering(true)); + alterResult = object->alter(elapsedTime); + DO_ON_OBJECT_ALTER_FLAG_SUPPORTED(object->setIsAltering(false)); + +#if defined(_WIN32) && defined(_DEBUG) + if (typeName) + PROFILER_BLOCK_LEAVE(profilerBlock); +#endif + + DO_ON_DEBUG(s_currentlyAlteringObject = NULL); + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + } + + //-- Get the next object. Can't do it before this because this object may remove the next object from the alter now list. + DO_ON_HARDCORE_VALIDATION(DEBUG_FATAL(!findObjectInAlterNowList(object), ("didn't find object in alter now list, unexpected."))); + nextObject = object->getNextFromAlterNowList(); + +#if VALIDATE_OBJECTS + if (nextObject != NULL) + { + DO_ON_HARDCORE_VALIDATION(DEBUG_FATAL(!findObjectInAlterNowList(nextObject), ("didn't find object in alter now list, unexpected."))); + validateObject(nextObject); + } +#endif + + //-- If we've already processed this entry in a previous iteration prior to a delete and restart, + // don't process this alter again. + if (alreadyProcessed) + return; + + //-- Validate post-alter assertions. + // Ensure the object hasn't crept into the schedule map. Only applicable if + // we haven't already processed this object prior to a loop restart (due to deleted object). + DEBUG_FATAL(OBJECT_SCHEDULE_TIME_MAP_ITERATOR(*object) != s_scheduleMap.end(), ("AlterScheduler: object pointer=[%p],id=[%s],template=[%s] was in schedule map immediately after alter, shouldn't happen.", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); + DO_ON_DEBUG(doPerObjectAlterReportCollection(object, alterResult)); + + //-- We will move items into the conclude list IF the object is going to do a conclude all. + + //-- Determine what happens next to the object based on alter()'s return value. + if (alterResult == AlterResult::cms_kill) //lint !e777 // Testing floats for equality. // This is okay. + { + IGNORE_RETURN(snprintf(s_crashReportInfo, sizeof(s_crashReportInfo) - 1, "Alter Killing: %s\n", object->getObjectTemplateName())); + s_crashReportInfo[sizeof(s_crashReportInfo) - 1] = '\0'; + + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::delete"); //lint !e578 // redeclarations // can't help. + + // Remove object from the world. + if (object->isInWorld()) + object->removeFromWorld(); + + // Remove object from alter scheduler. + IGNORE_RETURN(removeObject(*object)); + + delete object; + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + + //-- Since we deleted object, we may have deleted our next link to follow. Restart alter list processing. + // Yes, this could be very inefficient since execution could restart potentially as many times as there are + // objects in the list. In practice, this shouldn't be an issue because we typically delete several objects + // at the same time via this one delete call, meaning many deletes are covered by a single list traversal + // restart. + nextObject = s_alterNowListFirst->getNextFromAlterNowList(); + } + else + { + PROFILER_AUTO_BLOCK_DEFINE("AlterScheduler::scheduleNext"); //lint !e578 // redeclarations // can't help. + + //-- Unlink from alter now list. + object->removeFromAlterNowList(); + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + + if (concludeStyle == CS_all) + object->insertIntoConcludeList(s_concludeListFirst); + + // If we're always altering, set the effect alter result to "alter next frame", regardless + // of the real return value. Otherwise we do the normal thing and use the returned alter + // result. Note we've already checked for the alter-requested kill by this point, so we're + // not overwriting that. + + float effectiveAlterResult; + + //-- Check if this object was scheduled for an alter during processing of this loop. If so, + // then the object is already in the alter next frame map and there's nothing more to do; + // otherwise, figure out when to schedule it and add to schedule map. + if (!object->isInAlterNextFrameList()) + { + if (alterResult == AlterResult::cms_keepNoAlter) //lint !e777 // Testing floats for equality. // This is okay, we're using constants. + { + // Check if we're testing by scheduling no-alter values as some time in the future. + // If the no-alter schedule delay is non-zero, we really want to schedule alters for objects + // that request no alter. Typically this delay will be a large value (e.g. weeks into the future). + // The delay is in seconds. + int const futureAlterTime = ConfigSharedObject::getAlterSchedulerNoAlterScheduleDelay (); + effectiveAlterResult = (futureAlterTime > 0) ? static_cast(futureAlterTime) : alterResult; + } + else + effectiveAlterResult = alterResult; + + if (effectiveAlterResult != AlterResult::cms_keepNoAlter) //lint !e777 // Testing floats for equality. // This is okay, we're using constants. + { + // This object would like to be scheduled for an alter some time in the future. + + // Calculate absolute time for next scheduling. + ScheduleTime const dt = static_cast(effectiveAlterResult * cs_schedulerTicksPerSecond); + ScheduleTime const absoluteScheduleTime = s_currentTime + dt; + + // Add it to the schedule list for the specified scheduler time. + // If this object is NULL, it means it returned an AlterResult that indicated it should still be alive but it somehow got killed. +//DEBUG_REPORT_LOG(object->getNetworkId() != NetworkId::cms_invalid, ("[aitest] scheduling %s to alter at %lu (%lu + %lu)\n", +// object->getNetworkId().getValueString().c_str(), +// static_cast(absoluteScheduleTime), +// static_cast(s_currentTime), +// static_cast(dt))); + addToScheduleMap(*object, absoluteScheduleTime); + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + } + } + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::concludeAndRemoveAllConcludeEntries() +{ + PROFILER_AUTO_BLOCK_DEFINE("conclude"); + + Object *nextObject; + for (Object *object = s_concludeListFirst->getNextFromConcludeList(); object != NULL; object = nextObject) + { + //-- Conclude the object. + DO_ON_VALIDATE_OBJECTS(validateObject(object)); + object->conclude(); + + nextObject = object->getNextFromConcludeList(); + object->removeFromConcludeList(); + + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + } +} + +// ---------------------------------------------------------------------- + +void AlterScheduler::doAlterAndConcludeForAllObjects(float schedulerElapsedTime, ConcludeStyle concludeStyle, Object *objectToConclude) +{ + doPreAlterRecursionCheck(); + incrementSchedulerTimerByElapsedTime(schedulerElapsedTime); + moveReadyObjectsFromSchedulerToNextFrameList(); + +//DEBUG_REPORT_LOG(true, ("[aitest] Altering objects at %lu\n", static_cast(s_currentTime))); + + for (int schedulePhaseIndex = 0; schedulePhaseIndex < AS_MAX_SCHEDULE_PHASE_COUNT; ++schedulePhaseIndex) + { + moveObjectsFromAlterNextFrameListToAlterNowList(schedulePhaseIndex); + + DO_ON_DEBUG(s_totalObjectAlterCalls = 0); + + //-- Do an alter for the "alter now" list. + // MAIN ALTER PROCESSING LOOP. + { + PROFILER_AUTO_BLOCK_DEFINE("alter"); + + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + + Object *nextObject; + for (Object *object = s_alterNowListFirst->getNextFromAlterNowList(); object != NULL; object = nextObject) + alterSingleObject(object, concludeStyle, nextObject); + } + + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + } + + //-- Only call this on the last run. + if (s_postAlterHookFunction) + s_postAlterHookFunction(schedulerElapsedTime); + + if (concludeStyle == CS_all) + { + //-- Do a conclude on the conclude list. We must do all frame alters before we do a conclude. + // This is because an alter for an object later in the list may cause changes to an object earlier in the + // list, which will require an adjustment to conclude handling for the earlier object. + concludeAndRemoveAllConcludeEntries(); + } + else + { + if ((concludeStyle == CS_one) && objectToConclude) + { + PROFILER_AUTO_BLOCK_DEFINE("conclude"); + + DO_ON_VALIDATE_OBJECTS(validateObject(objectToConclude)); + objectToConclude->conclude(); + } + } + DO_ON_HARDCORE_VALIDATION(validateAllContainers()); + + doPostAlterRecursionCheck(); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.h b/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.h new file mode 100644 index 00000000..e85e00f9 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.h @@ -0,0 +1,112 @@ +// ====================================================================== +// +// AlterScheduler.h +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_AlterScheduler_H +#define INCLUDED_AlterScheduler_H + +// ====================================================================== + +// Enable AS_USE_HARDCORE_CONTAINER_VALIDATION by setting value to 1 if you +// believe the alter scheduler is not processing Objects properly. This will +// greatly slow down AlterScheduler performance but will highlight container +// corruption if and when it happens. + +#ifdef _DEBUG +# define AS_USE_HARDCORE_CONTAINER_VALIDATION 0 +#else +# define AS_USE_HARDCORE_CONTAINER_VALIDATION 0 +#endif + +#define AS_MAX_SCHEDULE_PHASE_COUNT 2 + +// ====================================================================== + +class Object; + +// ====================================================================== + +class AlterScheduler +{ +public: + + class ScheduleTimeComparator; + + typedef uint64 ScheduleTime; + typedef stdmultimap::fwd ScheduleTimeMap; + +public: + + static void install(); + + static void submitForAlter(Object &object); + static bool removeObject(Object &object); + + static void setObjectSchedulePhase(Object &object, int schedulePhaseIndex); + + static void alter(float schedulerElapsedTime); + static void alterAndConclude(float elapsedTime); + static void alterAllAndConcludeOne(float elapsedTime, Object * objectToConclude); + + typedef void (*PostAlterHookFunction) (float elapsedTime); + static void setPostAlterHookFunction (PostAlterHookFunction postAlterHookFunction); + + static void initializeScheduleTimeMapIterator(Object &object); + static bool isIteratorInScheduleTimeMap(void const *iterator); + + static bool findObjectInAlterNowList(Object const *object); + static bool findObjectInAlterNextFrameLists(Object const *object); + static bool findObjectInConcludeList(Object const *object); + static bool findObjectInScheduleTimeMap(Object const *object); + static uint32 findObject(Object const *object); + + static void validateAlterNowList(); + static void validateAlterNextFrameLists(); + static void validateConcludeList(); + static void validateScheduleTimeMap(); + static void validateAllContainers(); + + static float getTimeSinceLastFrame(); + + static void setMostRecentAlterTime(Object &object); + +#ifdef _DEBUG + + static bool reportObjectAlters(); + static void countObjectAlter(); + static void reportObjectAlter(Object const *object, char const * appearanceType, float appearanceResult, char const * controllerType, float controllerResult, char const * dynamicsType, float dynamicsResult, float childrenResult, float objectResult); + +#endif + +private: + + enum ConcludeStyle + { + CS_none, + CS_one, + CS_all + }; + +private: + + static void addToAlterNextFrameList(Object &object); + static void addToAlterNowList(Object &object); + static void addToScheduleMap(Object &object, ScheduleTime nextAlterTime); + + static void dumpScheduleMap(); + static void moveReadyObjectsFromSchedulerToNextFrameList(); + static void moveObjectsFromAlterNextFrameListToAlterNowList(int schedulePhaseIndex); + static void prepareListsForAlter(); + static void alterSingleObject(Object *object, ConcludeStyle concludeStyle, Object *&nextObject); + static void concludeAndRemoveAllConcludeEntries(); + static void doAlterAndConcludeForAllObjects(float schedulerElapsedTime, ConcludeStyle concludeStyle, Object *objectToConclude); + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.cpp b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.cpp new file mode 100644 index 00000000..47c87004 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.cpp @@ -0,0 +1,184 @@ +// ====================================================================== +// +// CachedNetworkId.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CachedNetworkId.h" + +#include "sharedObject/NetworkIdManager.h" + +#include + +const CachedNetworkId CachedNetworkId::cms_cachedInvalid (NetworkId::cms_invalid); +const NetworkId CachedNetworkId::cms_invalid(static_cast(0)); + +//---------------------------------------------------------------------- + +void CachedNetworkId::checkValidity() const +{ + if (!m_object) + return; + + DEBUG_FATAL(*this == NetworkId::cms_invalid, ("Invalid 0 network id")); + DEBUG_FATAL(*this != m_object->getNetworkId(), ("Cached validity check failed")); +} + +//---------------------------------------------------------------------- + +CachedNetworkId::CachedNetworkId() : +m_id(cms_invalid), +m_object(NULL) +{ +} + +// ---------------------------------------------------------- + +CachedNetworkId::CachedNetworkId(const NetworkId& id) : +m_id(id), +m_object(NULL) +{ +} + +// ---------------------------------------------------------- + +CachedNetworkId::CachedNetworkId(NetworkId::NetworkIdType value) : +m_id(value), +m_object(NULL) +{ + +} + +// ---------------------------------------------------------- + +CachedNetworkId::CachedNetworkId(const Object& object) : +m_id(object.getNetworkId()), +m_object(const_cast(&object)) +{ + +} + +// ---------------------------------------------------------- + +CachedNetworkId::CachedNetworkId(const std::string &value) : +m_id(value), +m_object(NULL) +{ + +} + +// ---------------------------------------------------------- + +CachedNetworkId::CachedNetworkId(const CachedNetworkId& rhs) : +m_id(rhs.m_id), +m_object(rhs.m_object) +{ + +} + +// ---------------------------------------------------------- + +CachedNetworkId& CachedNetworkId::operator= (const CachedNetworkId& rhs) +{ + if (this == &rhs) + return *this; + + m_id = rhs.m_id; + + m_object = rhs.m_object.getPointer(); + return *this; +} + +// ---------------------------------------------------------- + +CachedNetworkId& CachedNetworkId::operator= (const NetworkId& rhs) +{ + m_id = rhs; + m_object = NULL; + return *this; +} +// ---------------------------------------------------------- + +CachedNetworkId& CachedNetworkId::operator= (const Object& object) +{ + m_id = object.getNetworkId(); + m_object = const_cast(&object); + return *this; +} + +// ---------------------------------------------------------- + +CachedNetworkId::operator NetworkId const & ( void ) const +{ + return m_id; +} + +bool CachedNetworkId::operator == ( NetworkId const & id ) const +{ + return m_id == id; +} + +bool CachedNetworkId::operator != ( NetworkId const & id ) const +{ + return m_id != id; +} + +NetworkId::NetworkIdType CachedNetworkId::getValue() const +{ + return m_id.getValue(); +} + +std::string CachedNetworkId::getValueString() const +{ + return m_id.getValueString(); +} + +bool CachedNetworkId::operator < (const NetworkId& rhs) const +{ + return m_id < rhs; +} + +size_t CachedNetworkId::getHashValue() const +{ + return m_id.getHashValue(); +} + +bool CachedNetworkId::isValid() const +{ + return m_id.isValid(); +} + +bool CachedNetworkId::operator !() const +{ + return m_id.operator !(); +} + + + +// ---------------------------------------------------------- + +CachedNetworkId::~CachedNetworkId() +{ +} + +// ---------------------------------------------------------- + +Object* CachedNetworkId::getObject() const +{ + if (isValid()) // don't do a hash lookup if m_value == 0 + { + if (m_object) + return m_object; + m_object = NetworkIdManager::getObjectById(m_id); + + return m_object; + } + + return NULL; +} + +// ---------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.h b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.h new file mode 100644 index 00000000..1c6040d1 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkId.h @@ -0,0 +1,78 @@ +// ====================================================================== +// +// CachedNetworkId.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CachedNetworkId_H +#define INCLUDED_CachedNetworkId_H + +// ====================================================================== + +#include "sharedFoundation/NetworkId.h" +#include "sharedFoundation/Watcher.h" + +#include "sharedObject/Object.h" + +class CachedNetworkId; + +// ====================================================================== + +class CachedNetworkId +{ +public: + + static const CachedNetworkId cms_cachedInvalid; + static const NetworkId cms_invalid; + +public: + + CachedNetworkId (); + explicit CachedNetworkId (const NetworkId& id); + explicit CachedNetworkId (NetworkId::NetworkIdType value); + explicit CachedNetworkId (const Object &object); + explicit CachedNetworkId (const std::string &value); + CachedNetworkId (const CachedNetworkId&); + + ~CachedNetworkId(); + + CachedNetworkId& operator= (const CachedNetworkId&); + CachedNetworkId& operator= (const NetworkId&); + CachedNetworkId& operator= (const Object& object); + + operator NetworkId const & ( void ) const; + + bool operator == ( NetworkId const & id ) const; + bool operator != ( NetworkId const & id ) const; + bool operator < (const NetworkId& rhs) const; + bool operator !() const; + + NetworkId::NetworkIdType getValue() const; + std::string getValueString() const; + size_t getHashValue() const; + + size_t operator()(const CachedNetworkId & x) const; + + Object* getObject() const; + + bool isValid() const; + void checkValidity() const; + +private: + + NetworkId m_id; + + mutable Watcher m_object; +}; + +//---------------------------------------------------------------------- + +inline size_t CachedNetworkId::operator()(const CachedNetworkId & x) const +{ + return x.getHashValue(); +} + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/object/CachedNetworkIdArchive.h b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkIdArchive.h new file mode 100644 index 00000000..0572f626 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/CachedNetworkIdArchive.h @@ -0,0 +1,33 @@ +// CachedNetworkIdArchive.h +// copyright 2001 Verant Interactive +// Author: Justin Randall + +#ifndef INCLUDED_CachedNetworkIdArchive_H +#define INCLUDED_CachedNetworkIdArchive_H + +//----------------------------------------------------------------------- + +#include "Archive/ByteStream.h" +#include "sharedObject/CachedNetworkId.h" + +//----------------------------------------------------------------------- + +namespace Archive +{ + inline void get(ReadIterator & source, CachedNetworkId & target) + { + uint64 id; + source.get(&id,8); + target = CachedNetworkId(id); + } + + inline void put(ByteStream & target, const CachedNetworkId & source) + { + uint64 tmp = source.getValue(); + target.put(&tmp,8); + } +} + +//----------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/DebugNotification.cpp b/engine/shared/library/sharedObject/src/shared/object/DebugNotification.cpp new file mode 100644 index 00000000..45009a01 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/DebugNotification.cpp @@ -0,0 +1,86 @@ +// ====================================================================== +// +// DebugNotification.cpp +// Copyright 2003 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/DebugNotification.h" + +// ====================================================================== + +DebugNotification DebugNotification::ms_instance; + +// ====================================================================== + +DebugNotification & DebugNotification::getInstance() +{ + return ms_instance; +} + +// ====================================================================== + +DebugNotification::DebugNotification() +{ +} + +// ---------------------------------------------------------------------- + +DebugNotification::~DebugNotification() +{ +} + +// ---------------------------------------------------------------------- + +int DebugNotification::getPriority() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +void DebugNotification::addToWorld(Object &) const +{ +} + +// ---------------------------------------------------------------------- + +void DebugNotification::removeFromWorld(Object &) const +{ +} + +// ---------------------------------------------------------------------- + +bool DebugNotification::positionChanged(Object &, bool, const Vector &) const +{ + return true; +} + +// ---------------------------------------------------------------------- + +void DebugNotification::rotationChanged(Object &, bool) const +{ +} + +// ---------------------------------------------------------------------- + +bool DebugNotification::positionAndRotationChanged(Object &, bool, const Vector &) const +{ + return true; +} + +// ---------------------------------------------------------------------- + +void DebugNotification::cellChanged(Object &, bool) const +{ +} + +// ---------------------------------------------------------------------- + +void DebugNotification::extentChanged(Object &) const +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/DebugNotification.h b/engine/shared/library/sharedObject/src/shared/object/DebugNotification.h new file mode 100644 index 00000000..f12da4c6 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/DebugNotification.h @@ -0,0 +1,52 @@ +// ====================================================================== +// +// DebugNotifcation.h +// Copyright 2003 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_DebugNotifcation_H +#define INCLUDED_DebugNotifcation_H + +// ====================================================================== + +#include "sharedObject/ObjectNotification.h" + +// ====================================================================== + +class DebugNotification : public ObjectNotification +{ +public: + + static DebugNotification & getInstance(); + +public: + + DebugNotification(); + virtual ~DebugNotification(); + + virtual int getPriority() const; + + virtual void addToWorld(Object & object) const; + virtual void removeFromWorld(Object & object) const; + + virtual bool positionChanged(Object & object, bool dueToParentChange, const Vector & oldPosition) const; + virtual void rotationChanged(Object & object, bool dueToParentChange) const; + virtual bool positionAndRotationChanged(Object & object, bool dueToParentChange, const Vector & oldPosition) const; + virtual void cellChanged(Object & object, bool dueToParentChange) const; + virtual void extentChanged(Object & object) const; + +private: + + static DebugNotification ms_instance; + +private: + + DebugNotification(DebugNotification const &); + DebugNotification & operator=(DebugNotification const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.cpp b/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.cpp new file mode 100644 index 00000000..70fd7985 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.cpp @@ -0,0 +1,87 @@ +// ====================================================================== +// +// DebugYawedFloorNotification.cpp +// asommers +// +// copyright 2003, sony online entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/DebugYawedFloorNotification.h" + +#include "sharedCollision/CollisionProperty.h" +#include "sharedObject/Object.h" + +#include + +// ====================================================================== + +DebugYawedFloorNotification DebugYawedFloorNotification::ms_instance; + +// ====================================================================== +// STATIC PUBLIC DebugYawedFloorNotification +// ====================================================================== + +DebugYawedFloorNotification& DebugYawedFloorNotification::getInstance () +{ + return ms_instance; +} + +// ====================================================================== +// PUBLIC DebugYawedFloorNotification +// ====================================================================== + +DebugYawedFloorNotification::DebugYawedFloorNotification () : + ObjectNotification () +{ +} + +//------------------------------------------------------------------- + +DebugYawedFloorNotification::~DebugYawedFloorNotification () +{ +} + +//------------------------------------------------------------------- + +void DebugYawedFloorNotification::addToWorld (Object& object) const +{ + UNREF (object); + +#ifdef _DEBUG + if (object.isChildObject ()) + return; + + const CollisionProperty* const collisionProperty = object.getCollisionProperty (); + if (!collisionProperty) + return; + + if (collisionProperty->getFloor () && object.getObjectFrameJ_w ().dot (Vector::unitY) < 0.99f) + { + const Vector position_w = object.getPosition_w (); + DEBUG_WARNING (true, ("DebugYawedFloorNotification: object %s [%s] has a floor but is not oriented straight up at <%1.2f, %1.2f>", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName (), position_w.x, position_w.z)); + } +#endif +} + +// ---------------------------------------------------------------------- + +void DebugYawedFloorNotification::rotationChanged(Object &object, bool dueToParentChange) const +{ + if (dueToParentChange) + return; + + addToWorld (object); +} + +// ---------------------------------------------------------------------- + +bool DebugYawedFloorNotification::positionAndRotationChanged (Object& object, bool dueToParentChange, const Vector& /*oldPosition*/) const +{ + rotationChanged (object, dueToParentChange); + + return true; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.h b/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.h new file mode 100644 index 00000000..67d9f4d6 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/DebugYawedFloorNotification.h @@ -0,0 +1,46 @@ +// ====================================================================== +// +// DebugYawedFloorNotification.h +// asommers +// +// copyright 2003, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_DebugYawedFloorNotification_H +#define INCLUDED_DebugYawedFloorNotification_H + +// ====================================================================== + +#include "sharedObject/ObjectNotification.h" + +// ====================================================================== + +class DebugYawedFloorNotification : public ObjectNotification +{ +public: + + static DebugYawedFloorNotification& getInstance (); + +public: + + DebugYawedFloorNotification (); + virtual ~DebugYawedFloorNotification (); + + virtual void addToWorld (Object& object) const; + virtual void rotationChanged(Object &object, bool dueToParentChange) const; + virtual bool positionAndRotationChanged (Object& object, bool dueToParentChange, const Vector& oldPosition) const; + +private: + + DebugYawedFloorNotification (const DebugYawedFloorNotification&); + DebugYawedFloorNotification& operator= (const DebugYawedFloorNotification&); + +private: + + static DebugYawedFloorNotification ms_instance; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.cpp b/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.cpp new file mode 100644 index 00000000..828fdbe2 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.cpp @@ -0,0 +1,26 @@ +// ====================================================================== +// +// MemoryBlockManagedObject.cpp +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/MemoryBlockManagedObject.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(MemoryBlockManagedObject, true, 0, 0, 0); + +// ====================================================================== + +MemoryBlockManagedObject::MemoryBlockManagedObject() : + Object() +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.h b/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.h new file mode 100644 index 00000000..31ba7fbe --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/MemoryBlockManagedObject.h @@ -0,0 +1,52 @@ +// ====================================================================== +// +// MemoryBlockManagedObject.h +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_MemoryBlockManagedObject_H +#define INCLUDED_MemoryBlockManagedObject_H + +// ====================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedObject/Object.h" + +class MemoryBlockManager; + +// ====================================================================== +/** + * Provide a MemoryBlockManaged version of Object. + * + * This class adds no new behavior to Object except for the per-instance + * memory allocation scheme. + * + * The client frequently creates base Object instances for use in client-side + * effects. Object is not mem block managed. Making Object mem block managed + * with the existing macros will force us to mem block manage all Object-derived + * classes and will require changes to MemoryBlockManagerMacros implementation + * (due to the static ms_memoryBlockManager instance that is part of the class + * interface). ALS and TRF decided this was the most effective solution. + */ + +class MemoryBlockManagedObject: public Object +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + MemoryBlockManagedObject(); + +private: + + // Disabled. + MemoryBlockManagedObject(MemoryBlockManagedObject const&); + MemoryBlockManagedObject &operator =(MemoryBlockManagedObject const&); + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.cpp b/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.cpp new file mode 100644 index 00000000..c12cf501 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.cpp @@ -0,0 +1,103 @@ +// NetworkIdManager.cpp +// copyright 2001 Verant Interactive +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/NetworkIdManager.h" + +#include "sharedFoundation/NetworkId.h" +#include "sharedObject/Object.h" + +#include +#include + +//----------------------------------------------------------------------- + +NetworkIdManager NetworkIdManager::ms_instance; +bool NetworkIdManager::ms_reportObjectLeaks = true; + + +//---------------------------------------------------------------------- + +NetworkIdManager::NetworkIdManager() : +m_objectHashMap(new NetworkIdObjectHashMap) +{ + NOT_NULL(m_objectHashMap); +} + +//----------------------------------------------------------------------- + +NetworkIdManager::~NetworkIdManager() +{ + NOT_NULL(m_objectHashMap); + + if (ms_reportObjectLeaks) + { + NetworkIdObjectHashMap::iterator i = m_objectHashMap->begin(); + for (; i != m_objectHashMap->end(); ++i) + { + DEBUG_WARNING(true, ("Object %s wasn't removed cleanly from the game\n", i->second->getDebugInformation(true).c_str())); +// delete i->second; + } + } + + m_objectHashMap->clear(); + delete m_objectHashMap; +} + +//----------------------------------------------------------------------- + +NetworkIdManager & NetworkIdManager::getInstance () +{ + return ms_instance; +} + +//----------------------------------------------------------------------- + +void NetworkIdManager::addObject(Object & sourceObject) +{ + static NetworkIdManager & instance = getInstance(); + static NetworkIdObjectHashMap & map = *instance.m_objectHashMap; + if(sourceObject.getNetworkId() != NetworkId::cms_invalid) + { + WARNING_STRICT_FATAL(NetworkIdManager::getObjectById(sourceObject.getNetworkId()), ("Cannot add object with id %s because one already exists", sourceObject.getNetworkId().getValueString().c_str())); + IGNORE_RETURN(map.insert(std::pair(sourceObject.getNetworkId(), &sourceObject))); + } +} //lint !e1764 // sourceObject could be declared const ref // No, I need a non-const pointer to it. + +//----------------------------------------------------------------------- + +Object * NetworkIdManager::getObjectById(const NetworkId & source) +{ + static NetworkIdManager & instance = getInstance(); + static NetworkIdObjectHashMap & map = *instance.m_objectHashMap; + NetworkIdObjectHashMap::iterator i = map.find(source); + if(i != map.end()) + return (*i).second; + return 0; +} + +//----------------------------------------------------------------------- + +void NetworkIdManager::removeObject(const Object & sourceObject) +{ + static NetworkIdManager & instance = getInstance(); + static NetworkIdObjectHashMap & map = *instance.m_objectHashMap; + + if(sourceObject.getNetworkId() != NetworkId::cms_invalid) + map.erase(map.find(sourceObject.getNetworkId())); +} + +//----------------------------------------------------------------------- + +NetworkIdManager::NetworkIdObjectHashMap const & NetworkIdManager::getAllObjects() +{ + static NetworkIdManager & instance = getInstance(); + static NetworkIdObjectHashMap & map = *instance.m_objectHashMap; + + return map; +} + +//----------------------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.h b/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.h new file mode 100644 index 00000000..c362042f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/NetworkIdManager.h @@ -0,0 +1,48 @@ +// NetworkIdManager.h +// copyright 2001 Verant Interactive +// Author: Justin Randall + +#ifndef _INCLUDED_NetworkIdManager_H +#define _INCLUDED_NetworkIdManager_H + +#include "sharedFoundation/NetworkId.h" + +class Object; + +//----------------------------------------------------------------------- + +class NetworkIdManager +{ +public: + ~NetworkIdManager(); + + typedef stdhash_map::fwd NetworkIdObjectHashMap; + + static void addObject (Object & newObject); + static Object * getObjectById (const NetworkId & source); + static void removeObject (const Object & oldObject); + static NetworkIdObjectHashMap const & getAllObjects(); + + static void setReportObjectLeaks(bool reportObjectLeaks); + +protected: + NetworkIdManager(); + NetworkIdManager (const NetworkIdManager&); + static NetworkIdManager & getInstance (); + NetworkIdManager& operator= (const NetworkIdManager&); + +private: + NetworkIdObjectHashMap* const m_objectHashMap; + + static NetworkIdManager ms_instance; + static bool ms_reportObjectLeaks; +}; + +//---------------------------------------------------------------------- + +inline void NetworkIdManager::setReportObjectLeaks(bool reportObjectLeaks) +{ + ms_reportObjectLeaks = reportObjectLeaks; +} + +#endif // _INCLUDED_NetworkIdManager_H diff --git a/engine/shared/library/sharedObject/src/shared/object/Object.cpp b/engine/shared/library/sharedObject/src/shared/object/Object.cpp new file mode 100644 index 00000000..589f2291 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/Object.cpp @@ -0,0 +1,3388 @@ +// ====================================================================== +// +// Object.cpp +// copyright 1998 Bootprint Entertainment +// Copyright 2000-2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Object.h" + +#include "sharedCollision/CollisionProperty.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/DebugInfoManager.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/Production.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/DebugShapeRenderer.h" +#include "sharedMath/SpatialSubdivision.h" +#include "sharedMath/Sphere.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Controller.h" +#include "sharedObject/Dynamics.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectNotification.h" +#include "sharedObject/ObjectTemplate.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/ScheduleData.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/VolumeContainer.h" +#include "sharedObject/World.h" + +#include +#include +#include +#include +#include + +#define ENABLE_OBJECTTOWORLDDIRTY 1 +#define PROFILE_GETTRANSFORM_O2W 0 + +// ====================================================================== + +class Object::NotificationList +{ +public: + + NotificationList(); + NotificationList(const NotificationList &otherList, const ObjectNotification &otherEntry, bool addOtherEntry); + + bool equalsAdd(const NotificationList &otherList, const ObjectNotification &otherEntry) const; + bool equalsRemove(const NotificationList &otherList, const ObjectNotification &otherEntry) const; + bool contains(const ObjectNotification &otherEntry) const; + + void addToWorld(Object &object) const; + void removeFromWorld(Object &object) const; + + void positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + void rotationChanged(Object &object, bool dueToParentChange) const; + void positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + + void cellChanged(Object &object, bool dueToParentChange) const; + void extentChanged(Object &object) const; + void pobFixupComplete(Object &object) const; + +protected: + + typedef std::vector Notifications; + Notifications m_notificationList; +}; + +// ====================================================================== + +Object::NotificationList::NotificationList() +: m_notificationList() +{ +} + +// ---------------------------------------------------------------------- + +Object::NotificationList::NotificationList(const NotificationList &otherList, const ObjectNotification &otherEntry, bool addOtherEntry) +: m_notificationList() +{ + if (addOtherEntry) + { + // handle adding the other entry + + m_notificationList.reserve(otherList.m_notificationList.size() + 1); + + bool addedOtherEntry = false; + + const int otherPriority = otherEntry.getPriority(); + + // copy the other notification list, inserting the other entry in sorted position + const Notifications::const_iterator end = otherList.m_notificationList.end(); + for (Notifications::const_iterator i = otherList.m_notificationList.begin(); i != end; ++i) + { + const ObjectNotification *add = *i; + const int addPriority = add->getPriority(); + + if (!addedOtherEntry && (otherPriority < addPriority || (otherPriority == addPriority && &otherEntry < add))) + { + m_notificationList.push_back(&otherEntry); + addedOtherEntry = true; + } + + m_notificationList.push_back(add); + } + + // if the other entry didn't get copied already, it's the last element + if (!addedOtherEntry) + m_notificationList.push_back(&otherEntry); + + DEBUG_FATAL(m_notificationList.size() != otherList.m_notificationList.size() + 1, ("failed to build new notification list correctly")); + } + else + { + // handle creating a copy but deleting the other entry + m_notificationList.reserve(otherList.m_notificationList.size() - 1); + + bool deletedOtherEntry = false; + + // copy the other notification list, deleting the other entry if found + const Notifications::const_iterator end = otherList.m_notificationList.end(); + for (Notifications::const_iterator i = otherList.m_notificationList.begin(); i != end; ++i) + { + const ObjectNotification *add = *i; + if (add == &otherEntry) + { + // skip it --- we are removing this notification + deletedOtherEntry = true; + continue; + } + + // copy the source notification + m_notificationList.push_back(add); + } + + DEBUG_FATAL(!deletedOtherEntry, ("didn't find notification [0x%08x] in source list for deletion", &otherEntry)); + DEBUG_FATAL(m_notificationList.size() != otherList.m_notificationList.size() - 1, ("failed to build new notification list correctly")); + + } +} + +// ---------------------------------------------------------------------- + +bool Object::NotificationList::equalsAdd(const NotificationList &otherList, const ObjectNotification &otherEntry) const +{ + return otherList.equalsRemove(*this, otherEntry); +} + +// ---------------------------------------------------------------------- + +bool Object::NotificationList::equalsRemove(const NotificationList &otherList, const ObjectNotification &otherEntry) const +{ + const uint otherSize = otherList.m_notificationList.size(); + if (m_notificationList.size() + 1 != otherSize) + return false; + + // compare against the other list and the other entry + bool once = false; + uint i = 0; + uint j = 0; + for ( ; i < otherSize; ++i) + { + if (otherList.m_notificationList[i] == &otherEntry) + { + // go on to next local element + DEBUG_FATAL(once, ("found other entry twice")); + once = true; + } + else + if (j < otherSize-1 && otherList.m_notificationList[i] == m_notificationList[j]) + ++j; + else + return false; + } + + // make sure the item to remove was found + if (!once) + return false; + + return true; +} + +// ---------------------------------------------------------------------- + +bool Object::NotificationList::contains(const ObjectNotification &otherEntry) const +{ + return std::find(m_notificationList.begin(), m_notificationList.end(), &otherEntry) != m_notificationList.end(); +} + +// ---------------------------------------------------------------------- +/** + * Return whether the object is initialized or not. + * + * Uninitialized objects should not be processed by the AlterScheduler + * nor should their alter calls be made. + */ + +bool Object::isInitialized() const +{ + //-- By default, all objects are initialized. Derived classes can override + // this behavior and should not chain down to Object::isInitialized(). + return true; +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::addToWorld(Object &object) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + (*i)->addToWorld(object); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::removeFromWorld(Object &object) const +{ + Notifications::const_reverse_iterator end = m_notificationList.rend(); + for (Notifications::const_reverse_iterator i = m_notificationList.rbegin(); i != end; ++i) + (*i)->removeFromWorld(object); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + if (!(*i)->positionChanged(object, dueToParentChange, oldPosition)) + return; +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::rotationChanged(Object &object, bool dueToParentChange) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + (*i)->rotationChanged(object, dueToParentChange); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + if (!(*i)->positionAndRotationChanged(object, dueToParentChange, oldPosition)) + return; +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::cellChanged(Object &object, bool dueToParentChange) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + (*i)->cellChanged(object, dueToParentChange); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::extentChanged(Object &object) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + (*i)->extentChanged(object); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationList::pobFixupComplete(Object &object) const +{ + Notifications::const_iterator end = m_notificationList.end(); + for (Notifications::const_iterator i = m_notificationList.begin(); i != end; ++i) + (*i)->pobFixupComplete(object); +} + +// ====================================================================== + +class Object::NotificationListManager +{ +public: + + static void install(); + + static const NotificationList *getEmptyNotificationList(); + static const NotificationList *addNotification(const NotificationList *notificationList, const ObjectNotification ¬ification); + static const NotificationList *removeNotification(const NotificationList *notificationList, const ObjectNotification ¬ification); + +public: + + typedef std::vector List; + +private: + + static void remove(); + +private: + + static List ms_list; + static Object::NotificationList ms_empty; +}; + +// ====================================================================== + +Object::NotificationListManager::List Object::NotificationListManager::ms_list; +Object::NotificationList Object::NotificationListManager::ms_empty; + +// ====================================================================== + +void Object::NotificationListManager::install() +{ + ms_list.push_back(&ms_empty); + ExitChain::add(remove, "Object::NotificationListManager::remove"); +} + +// ---------------------------------------------------------------------- + +void Object::NotificationListManager::remove() +{ + // don't delete the first element, it wasn't allocated from the heap + const uint count = ms_list.size(); + for (uint i = 1; i < count; ++i) + { + const NotificationList *notificationList = ms_list.back(); + ms_list.pop_back(); + delete notificationList; //lint !e605 // Increase in pointer capability + } + + // remove the first element from the list + ms_list.pop_back(); +} + +// ====================================================================== + +const Object::NotificationList *Object::NotificationListManager::getEmptyNotificationList() +{ + return &ms_empty; +} + +// ---------------------------------------------------------------------- + +const Object::NotificationList *Object::NotificationListManager::addNotification(const NotificationList *source, const ObjectNotification ¬ification) +{ + const List::const_iterator end = ms_list.end(); + + // search for an existing copy of the requested notification list + for (List::const_iterator i = ms_list.begin(); i != end; ++i) + if ((*i)->equalsAdd(*source, notification)) + return *i; + + // wasn't found, create one + NotificationList *notificationList = new NotificationList(*source, notification, true); + ms_list.push_back(notificationList); + + return notificationList; +} + +// ---------------------------------------------------------------------- + +const Object::NotificationList *Object::NotificationListManager::removeNotification(const NotificationList *source, const ObjectNotification ¬ification) +{ + const List::const_iterator end = ms_list.end(); + + // search for an existing copy of the requested notification list + for (List::const_iterator i = ms_list.begin(); i != end; ++i) + if ((*i)->equalsRemove(*source, notification)) + return *i; + + // wasn't found, create one + NotificationList *notificationList = new NotificationList(*source, notification, false); + ms_list.push_back(notificationList); + + return notificationList; +} + +// ====================================================================== + +namespace ObjectNamespace +{ + typedef std::vector DpvsObjectsList; + typedef std::map PropertySearchStatistics; + typedef std::vector PropertyList; + typedef std::vector PropertyListList; + typedef stdvector::fwd AttachedObjects; + typedef stdvector::fwd AttachedObjectsList; + + MemoryBlockManager *ms_transformMemoryBlockManager; + DpvsObjectsList ms_systemAllocatedDpvsObjectsList; + int ms_allocatedDpvsObjects; + DpvsObjectsList ms_freeDpvsObjectsList; + PropertyListList ms_propertyListList; + AttachedObjectsList ms_attachedObjectsList; + bool ms_disallowObjectDelete; + bool ms_logObjectDelete; + bool ms_validateObjectPosition; + bool ms_objectsAlterChildrenAndContents; + + PropertySearchStatistics ms_propertySearchStatistics; + int ms_propertySearchesPerFrame; + bool ms_reportPropertySearchStatistics; + + Object::InWorldAddDpvsObjectHookFunction ms_inWorldAddDpvsObjectHookFunction; + Object::InWorldRemoveDpvsObjectHookFunction ms_inWorldRemoveDpvsObjectHookFunction; + Object::LeakedDpvsObjectHookFunction ms_leakedDpvsObjectHookFunction; + + char ms_crashReportInfo[MAX_PATH * 2]; + + void remove(); + Transform *newLocalTransform(); + void deleteLocalTransform(Transform *t); + Object::DpvsObjects *newDpvsObjects(); + void deleteDpvsObjects(Object::DpvsObjects *t); + PropertyList * newPropertyList(); + void deletePropertyList(PropertyList * propertyList); + AttachedObjects * newAttachedObjects(); + void deleteAttachedObjects(AttachedObjects * attachedObjects); + void reportPropertySearchStatistics(); + void validatePosition(Object const & object, Vector const & position); + AxialBox const getTangibleExtentInternal(Object const &obj); + +#if PROFILE_GETTRANSFORM_O2W == 1 + bool ms_debugReport; + int ms_totalCalls; + int ms_totalAttachedCalls; + int ms_totalAttachedDirtyCalls; + + void debugReport(); +#endif + + std::string const & ms_debugInfoSectionName = "Object"; +} +using namespace ObjectNamespace; + +// ====================================================================== + +void Object::install(bool objectsAlterChildrenAndContents) +{ + NotificationListManager::install(); + ms_transformMemoryBlockManager = new MemoryBlockManager("Object::ms_transformMemoryBlockManager", true, sizeof(Transform), 0, 0, 0); + ms_objectsAlterChildrenAndContents = objectsAlterChildrenAndContents; + ExitChain::add(&ObjectNamespace::remove, "Object::remove"); + DebugFlags::registerFlag(ms_objectsAlterChildrenAndContents, "SharedObject", "objectsAlterChildrenAndContents"); + DebugFlags::registerFlag(ms_reportPropertySearchStatistics, "SharedObject", "reportPropertySearchStatistics", reportPropertySearchStatistics); + DebugFlags::registerFlag(ms_logObjectDelete, "SharedObject", "logObjectDelete"); + DebugFlags::registerFlag(ms_validateObjectPosition, "SharedObject", "validateObjectPosition"); +#if PROFILE_GETTRANSFORM_O2W == 1 + DebugFlags::registerFlag(ms_debugReport, "SharedObject/Object", "debugReport", ObjectNamespace::debugReport); +#endif + + ms_crashReportInfo[0] = '\0'; + CrashReportInformation::addDynamicText(ms_crashReportInfo); +} + +// ---------------------------------------------------------------------- + +bool Object::shouldObjectsAlterChildrenAndContents() +{ + return ms_objectsAlterChildrenAndContents; +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::reportPropertySearchStatistics() +{ + DEBUG_REPORT_PRINT(true, ("Object property searches (%d):\n", ms_propertySearchesPerFrame)); + ms_propertySearchesPerFrame = 0; + PropertySearchStatistics ::const_iterator const iEnd = ms_propertySearchStatistics.end(); + for (PropertySearchStatistics::const_iterator i = ms_propertySearchStatistics.begin(); i != iEnd; ++i) + DEBUG_REPORT_PRINT(true, (" %08lx %d\n", i->first, i->second)); +} + +// ---------------------------------------------------------------------- + +#if PROFILE_GETTRANSFORM_O2W == 1 + +void ObjectNamespace::debugReport() +{ + DEBUG_REPORT_PRINT(true, ("totalCalls=%d\n", ms_totalCalls)); + DEBUG_REPORT_PRINT(true, ("totalAttachedCalls=%d\n", ms_totalAttachedCalls)); + DEBUG_REPORT_PRINT(true, ("totalAttachedDirtyCalls=%d\n", ms_totalAttachedDirtyCalls)); +} + +#endif + +// ---------------------------------------------------------------------- + +void ObjectNamespace::remove() +{ + CrashReportInformation::removeDynamicText(ms_crashReportInfo); + + DebugFlags::unregisterFlag(ms_objectsAlterChildrenAndContents); + DebugFlags::unregisterFlag(ms_reportPropertySearchStatistics); + DebugFlags::unregisterFlag(ms_logObjectDelete); + DebugFlags::unregisterFlag(ms_validateObjectPosition); +#if PROFILE_GETTRANSFORM_O2W == 1 + DebugFlags::unregisterFlag(ms_debugReport); +#endif + + delete ms_transformMemoryBlockManager; + ms_transformMemoryBlockManager = NULL; + + DEBUG_WARNING(static_cast(ms_freeDpvsObjectsList.size()) != ms_allocatedDpvsObjects, ("Leaked %d DpvsObjects lists", ms_allocatedDpvsObjects - static_cast(ms_freeDpvsObjectsList.size()))); + while (!ms_systemAllocatedDpvsObjectsList.empty()) + { + delete [] ms_systemAllocatedDpvsObjectsList.back(); + ms_systemAllocatedDpvsObjectsList.pop_back(); + } + + while (!ms_propertyListList.empty()) + { + delete ms_propertyListList.back(); + ms_propertyListList.pop_back(); + } + + while (!ms_attachedObjectsList.empty()) + { + delete ms_attachedObjectsList.back(); + ms_attachedObjectsList.pop_back(); + } +} + +// ---------------------------------------------------------------------- + +Transform *ObjectNamespace::newLocalTransform() +{ + void *memory = ms_transformMemoryBlockManager->allocate(); + return new(memory) Transform; +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::deleteLocalTransform(Transform *transform) +{ + void *const transformMemory = transform; + transform->~Transform(); + + ms_transformMemoryBlockManager->free(transformMemory); +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::validatePosition(Object const & object, Vector const & position) +{ + if (abs(position.x) > 16000.0f || abs(position.y) > 16000.0f || abs(position.z) > 16000.0f) + { + Object const * parent = object.getAttachedTo(); + + WARNING_STRICT_FATAL(ms_validateObjectPosition, ("Position (%f,%f,%f) is out-of-world and is invalid for object id=[%s], template=[%s], pointer=[%p], appearance=[%s], parent id=[%s], template=[%s], pointer=[%p], appearance=[%s]\n", + position.x, + position.y, + position.z, + object.getNetworkId().getValueString().c_str(), + object.getObjectTemplateName(), + &object, + object.getAppearance() ? object.getAppearance()->getAppearanceTemplateName() : NULL, + parent ? parent->getNetworkId().getValueString().c_str() : NULL, + parent ? parent->getObjectTemplateName() : NULL, + parent ? parent : NULL, + parent && parent->getAppearance() ? parent->getAppearance()->getAppearanceTemplateName() : NULL)); + } +} + +// ---------------------------------------------------------------------- + +Object::DpvsObjects *ObjectNamespace::newDpvsObjects() +{ + if (ms_freeDpvsObjectsList.empty()) + { + // allocate them in bulk from the global memory manager + const int count = 256; + Object::DpvsObjects *dpvsObjectListArray = new Object::DpvsObjects[count]; + ms_systemAllocatedDpvsObjectsList.push_back(dpvsObjectListArray); + ms_allocatedDpvsObjects += count; + for (int i = 0; i < count; ++i) + ms_freeDpvsObjectsList.push_back(dpvsObjectListArray+i); + } + + Object::DpvsObjects *result = ms_freeDpvsObjectsList.back(); + ms_freeDpvsObjectsList.pop_back(); + return result; +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::deleteDpvsObjects(Object::DpvsObjects *dpvsObjectList) +{ + if (!dpvsObjectList->empty()) + { + DEBUG_FATAL(true, ("leaked [%d] dpvsObjects", static_cast(dpvsObjectList->size()))); + dpvsObjectList->clear(); //lint !e527 // unreachable // Reachable in release. + } + ms_freeDpvsObjectsList.push_back(dpvsObjectList); +} + +// ---------------------------------------------------------------------- + +PropertyList * ObjectNamespace::newPropertyList() +{ + if (ms_propertyListList.empty()) + { + for (int i = 0; i < 256; ++i) + ms_propertyListList.push_back(new PropertyList); + } + + PropertyList * const result = ms_propertyListList.back(); + ms_propertyListList.pop_back(); + + return result; +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::deletePropertyList(PropertyList * const propertyList) +{ + if (ms_propertyListList.size() < 256) + { + DEBUG_FATAL(!propertyList->empty(), ("propertyList is not empty")); + propertyList->clear(); + ms_propertyListList.push_back(propertyList); + } + else + delete propertyList; +} + +// ---------------------------------------------------------------------- + +AttachedObjects * ObjectNamespace::newAttachedObjects() +{ + if (ms_attachedObjectsList.empty()) + { + for (int i = 0; i < 256; ++i) + ms_attachedObjectsList.push_back(new AttachedObjects); + } + + AttachedObjects * const result = ms_attachedObjectsList.back(); + ms_attachedObjectsList.pop_back(); + + return result; +} + +// ---------------------------------------------------------------------- + +void ObjectNamespace::deleteAttachedObjects(AttachedObjects * const attachedObjects) +{ + if (ms_attachedObjectsList.size() < 256) + { + DEBUG_FATAL(!attachedObjects->empty(), ("attachedObjects is not empty")); + attachedObjects->clear(); + ms_attachedObjectsList.push_back(attachedObjects); + } + else + delete attachedObjects; +} + +// ---------------------------------------------------------------------- + +void Object::setDpvsObjectHookFunctions(InWorldAddDpvsObjectHookFunction inWorldAddDpvsObjectHookFunction, InWorldRemoveDpvsObjectHookFunction inWorldRemoveDpvsObjectHookFunction, LeakedDpvsObjectHookFunction leakedDpvsObjectHookFunction) +{ + ms_inWorldAddDpvsObjectHookFunction = inWorldAddDpvsObjectHookFunction; + ms_inWorldRemoveDpvsObjectHookFunction = inWorldRemoveDpvsObjectHookFunction; + ms_leakedDpvsObjectHookFunction = leakedDpvsObjectHookFunction; +} + +// ---------------------------------------------------------------------- + +void Object::setDisallowObjectDelete(bool const disallowObjectDelete) +{ + ms_disallowObjectDelete = disallowObjectDelete; +} + +// ====================================================================== +// Construct an object + +Object::Object(): + m_propertyList(newPropertyList()), + m_inWorld(false), + m_active(true), + m_kill(false), + m_authoritative(false), + m_childObject(false), + m_objectToWorldDirty(true), +#if OBJECT_SUPPORTS_DESTROYED_FLAG + m_isDestroyed(false), +#endif +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + m_isAltering(false), +#endif + m_objectTemplate(NULL), + m_notificationList(NotificationListManager::getEmptyNotificationList()), + m_debugName(NULL), + m_networkId(NetworkId::cms_invalid), + m_appearance(NULL), + m_controller(NULL), + m_dynamics(NULL), + m_attachedToObject(NULL), + m_attachedObjects(NULL), + m_dpvsObjects(NULL), + m_rotations(0), + m_scale(Vector::xyz111), + m_objectToParent(), + m_objectToWorld(NULL), + m_watchedByList(), + m_containerProperty(NULL), + m_collisionProperty(NULL), + m_spatialSubdivisionHandle (0), + m_useAlterScheduler(true), + m_scheduleData(NULL), + m_shouldBakeIntoMesh(true), + m_defaultAppearance(NULL), + m_alternateAppearance(NULL), + m_containedBy(NULL) +{ + m_defaultAppearance = m_appearance; +} + +// ---------------------------------------------------------------------- + +Object::Object(const ObjectTemplate *objectTemplate, const NetworkId &networkId): + m_propertyList(newPropertyList()), + m_inWorld(false), + m_active(true), + m_kill(false), + m_authoritative(false), + m_childObject(false), + m_objectToWorldDirty(true), +#if OBJECT_SUPPORTS_DESTROYED_FLAG + m_isDestroyed(false), +#endif +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + m_isAltering(false), +#endif + m_objectTemplate(objectTemplate), + m_notificationList(NotificationListManager::getEmptyNotificationList()), + m_debugName(0), + m_networkId(networkId), + m_appearance(0), + m_controller(NULL), + m_dynamics(NULL), + m_attachedToObject(NULL), + m_attachedObjects(NULL), + m_dpvsObjects(NULL), + m_rotations(0), + m_scale(Vector::xyz111), + m_objectToParent(), + m_objectToWorld(NULL), + m_watchedByList(), + m_containerProperty(NULL), + m_collisionProperty(NULL), + m_spatialSubdivisionHandle (0), + m_useAlterScheduler(true), + m_scheduleData(NULL), + m_shouldBakeIntoMesh(true), + m_defaultAppearance(NULL), + m_alternateAppearance(NULL), + m_containedBy(NULL) +{ + objectTemplate->addReference(); + NetworkIdManager::addObject(*this); + + m_defaultAppearance = m_appearance; +} + +// ---------------------------------------------------------------------- + +Object::Object(const ObjectTemplate *objectTemplate, InitializeFlag): + m_propertyList(newPropertyList()), + m_inWorld(false), + m_active(true), + m_kill(false), + m_authoritative(false), + m_childObject(false), + m_objectToWorldDirty(true), +#if OBJECT_SUPPORTS_DESTROYED_FLAG + m_isDestroyed(false), +#endif +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + m_isAltering(false), +#endif + m_objectTemplate(objectTemplate), + m_notificationList(NotificationListManager::getEmptyNotificationList()), + m_debugName(0), + m_networkId(NetworkId::cms_invalid), + m_appearance(0), + m_controller(NULL), + m_dynamics(NULL), + m_attachedToObject(NULL), + m_attachedObjects(NULL), + m_dpvsObjects(NULL), + m_rotations(0), + m_scale(Vector::xyz111), + m_objectToParent(), + m_objectToWorld(NULL), + m_watchedByList(), + m_containerProperty(NULL), + m_collisionProperty(NULL), + m_spatialSubdivisionHandle (0), + m_useAlterScheduler(true), + m_scheduleData(NULL), + m_shouldBakeIntoMesh(true), + m_defaultAppearance(NULL), + m_alternateAppearance(NULL), + m_containedBy(NULL) +{ + objectTemplate->addReference(); + NetworkIdManager::addObject(*this); + + m_defaultAppearance = m_appearance; +} + +// ---------------------------------------------------------------------- +/** + * Destroy an object. + */ + +Object::~Object(void) +{ + //-- Store the name of hte most recently deleted object so we can track down live crashes if it fails somewhere in here. + IGNORE_RETURN(snprintf(ms_crashReportInfo, sizeof(ms_crashReportInfo) - 1, "~Object: name=[%s] template=[%s]\n", getDebugName(), getObjectTemplateName())); + ms_crashReportInfo[sizeof(ms_crashReportInfo) - 1] = '\0'; + + DEBUG_REPORT_LOG(ms_logObjectDelete, ("Deleting object id=[%s], template=[%s], pointer=[%p], appearance=[%s], parent id=[%s], template=[%s], pointer=[%p], appearance=[%s]\n", getNetworkId().getValueString().c_str(), getObjectTemplateName(), this, getAppearance() ? getAppearance()->getAppearanceTemplateName() : NULL, m_attachedToObject ? m_attachedToObject->getNetworkId().getValueString().c_str() : NULL, m_attachedToObject ? m_attachedToObject->getObjectTemplateName() : NULL, m_attachedToObject ? m_attachedToObject : NULL, m_attachedToObject && m_attachedToObject->getAppearance() ? m_attachedToObject->getAppearance()->getAppearanceTemplateName() : NULL)); + FATAL(ConfigSharedObject::getAllowDisallowObjectDelete() && ms_disallowObjectDelete, ("Object id=[%s], template=[%s], pointer=[%p] is deleting itself when delete is not allowed", getNetworkId().getValueString().c_str(), getObjectTemplateName(), this)); + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + FATAL(m_isAltering, ("Object id=[%s], template=[%s], pointer=[%p] is deleting itself while it is getting altered. Unsupported, fix object.", getNetworkId().getValueString().c_str(), getObjectTemplateName(), this)); +#endif + + if (m_inWorld) + Object::removeFromWorld(); + + if (m_scheduleData) + { + bool const wasInAlterScheduler = AlterScheduler::removeObject(*this); + UNREF(wasInAlterScheduler); + + delete m_scheduleData; + m_scheduleData = 0; + } + +#if OBJECT_SUPPORTS_DESTROYED_FLAG + // make sure we can tell this object is getting destroyed. + m_isDestroyed = true; +#endif + + // remove object from parent (make sure it's in the world cell) + if (m_attachedToObject) + { + detachFromObject(DF_world); + m_attachedToObject = 0; + } + + // destroy all the properties + while(!m_propertyList->empty()) + { + Property * p = m_propertyList->back(); + m_propertyList->pop_back(); + delete p; + } + m_containerProperty = 0; + m_collisionProperty = 0; + m_containedBy = 0; + + deletePropertyList(m_propertyList); + + if(m_defaultAppearance) + delete m_defaultAppearance; + if(m_alternateAppearance) + delete m_alternateAppearance; + + m_appearance = 0; + m_defaultAppearance = 0; + m_alternateAppearance = 0; + + // destroy children + if (m_attachedObjects) + { + while (!m_attachedObjects->empty()) + { + Object *child = m_attachedObjects->back(); + if (!child->isChildObject()) + { + WARNING_STRICT_FATAL(true, ("deleting object with non-child attached objects, parent id=[%s], objectTemplate=[%s], appearanceTemplate=[%s], child id=[%s], ptr=[0x%08x], objectTemplate=[%s], appearanceTemplate=[%s], name=[%s])", getNetworkId().getValueString().c_str(), getObjectTemplateName(), getAppearance() && getAppearance()->getAppearanceTemplate() ? getAppearance()->getAppearanceTemplate()->getName() : 0, child->getNetworkId().getValueString().c_str(), child, child->getObjectTemplateName(), child->getAppearance() && child->getAppearance()->getAppearanceTemplate() ? child->getAppearance()->getAppearanceTemplate()->getName() : 0, child->getDebugName())); + child->detachFromObject(DF_parent); + } + else + { + delete child; + } + } + + deleteAttachedObjects(m_attachedObjects); + m_attachedObjects = NULL; + } + + if (m_objectToWorld) + { + deleteLocalTransform(m_objectToWorld); + m_objectToWorld = 0; + } + + if (m_objectTemplate != NULL) + m_objectTemplate->releaseReference(); + m_objectTemplate = NULL; + + m_notificationList = 0; + + if (m_dpvsObjects) + { + if (!m_dpvsObjects->empty()) + { + WARNING(true, ("Object still has %d DPVS objects attached", static_cast(m_dpvsObjects->size()))); + + if (ms_leakedDpvsObjectHookFunction) + { + DpvsObjects::iterator const iEnd = m_dpvsObjects->end(); + for (DpvsObjects::iterator i = m_dpvsObjects->begin(); i != iEnd; ++i) + { + ms_leakedDpvsObjectHookFunction(*i); + } + } + + m_dpvsObjects->clear(); + + } + + deleteDpvsObjects(m_dpvsObjects); + m_dpvsObjects = 0; + } + + delete m_controller; + m_controller = 0; + + delete m_dynamics; + m_dynamics = 0; + + delete [] m_debugName; + m_debugName = 0; + + NetworkIdManager::removeObject(*this); + + m_spatialSubdivisionHandle = 0; +} + +// ---------------------------------------------------------------------- + +#if OBJECT_SUPPORTS_DESTROYED_FLAG + +bool Object::isDestroyed() const +{ + return m_isDestroyed; +} + +#endif + +// ---------------------------------------------------------------------- + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + +bool Object::isAltering() const +{ + return m_isAltering; +} + +#endif + +// ---------------------------------------------------------------------- +/** + * Set a new name for the object. + * + * If the object had a name, that name will be deleted. The new name will + * be copied into a dynamically allocated buffer using DuplicateString(). + * + * @param newName New name for the object + */ + +void Object::setDebugName(const char *newName) +{ + delete [] m_debugName; + m_debugName = 0; + + if (newName) + m_debugName = DuplicateString(newName); +} + +// ---------------------------------------------------------------------- + +std::string const Object::getDebugInformation(bool const includeParent) const +{ + char buffer[512]; + + if (includeParent && m_attachedToObject) + { + IGNORE_RETURN(snprintf(buffer, sizeof(buffer) - 1, "[ptr=%p, id=%s, ot=%s, at=%s, child=%i, pptr=%p, pid=%s, pot=%s, pat=%s]", + this, + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + getAppearanceTemplateName(), + isChildObject() ? 1 : 0, + m_attachedToObject, + m_attachedToObject->getNetworkId().getValueString().c_str(), + m_attachedToObject->getObjectTemplateName(), + m_attachedToObject->getAppearanceTemplateName())); + } + else + { + IGNORE_RETURN(snprintf(buffer, sizeof(buffer) - 1, "[ptr=%p, id=%s, ot=%s, at=%s]", + this, + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + getAppearanceTemplateName())); + } + + buffer[sizeof(buffer) - 1] = '\0'; + + return buffer; +} + +// ---------------------------------------------------------------------- + +bool Object::hasNotification(const ObjectNotification ¬ification) const +{ + return m_notificationList->contains(notification); +} + +// ---------------------------------------------------------------------- + +void Object::addNotification(const ObjectNotification ¬ification, bool allowWhenInWorld) +{ + UNREF(allowWhenInWorld); + DEBUG_FATAL(m_inWorld && !allowWhenInWorld, ("Cannot change notification while part of the world")); + + if (m_notificationList->contains(notification)) + { + DEBUG_WARNING(true, ("Adding notification that is already present")); + return; + } + m_notificationList = NotificationListManager::addNotification(m_notificationList, notification); +} + +// ---------------------------------------------------------------------- + +void Object::removeNotification(const ObjectNotification ¬ification, bool allowWhenInWorld) +{ + UNREF(allowWhenInWorld); + DEBUG_FATAL(m_inWorld && !allowWhenInWorld, ("Cannot change notification while part of the world")); + DEBUG_FATAL(!m_notificationList->contains(notification), ("Removing notification that does not exist")); + m_notificationList = NotificationListManager::removeNotification(m_notificationList, notification); +} + +// ---------------------------------------------------------------------- + +void Object::addToWorld() +{ + if (m_inWorld) + { + DEBUG_WARNING(true, ("Object (%s : %s) is already in the world.", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + return; + } + + setObjectToWorldDirty(true); + + m_inWorld = true; + + if (m_appearance) + m_appearance->addToWorld(); + + { + PropertyList::iterator iEnd = m_propertyList->end(); + for (PropertyList::iterator i = m_propertyList->begin(); i != iEnd; ++i) + (*i)->addToWorld(); + } + + m_notificationList->addToWorld(*this); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects::iterator iEnd = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != iEnd; ++i) + // Do not add attached child objects that are already in the world. + // This happens when an object has a PortalProperty in its PropertyList. + if ((*i)->isChildObject() && !(*i)->isInWorld()) + (*i)->addToWorld(); + } +} + +// ---------------------------------------------------------------------- +/** + * Remove an object from the world. + * + * The notifications will be called in the reverse order. + */ + +void Object::removeFromWorld() +{ + if (!m_inWorld) + { + WARNING_STRICT_FATAL(true, ("Object %s not in the world", getDebugInformation(true).c_str())); + return; + } + + setObjectToWorldDirty(true); + + { + for (PropertyList::iterator i = m_propertyList->begin(); i != m_propertyList->end(); ++i) + (*i)->removeFromWorld(); + } + + m_notificationList->removeFromWorld(*this); + + if (m_appearance) + m_appearance->removeFromWorld(); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects temp(*m_attachedObjects); + const AttachedObjects::const_iterator end = temp.end(); + for (AttachedObjects::const_iterator i = temp.begin(); i != end; ++i) + { + Object *attached= *i; + if (attached->isChildObject()) + attached->removeFromWorld(); + else + { + if (attached->isInWorld()) + { + DEBUG_WARNING(true, ("Removing an object [id=%s template=%s] from the world with non-child attached objects [id=%s ptr=0x%08x template=%s name=%s]", getNetworkId ().getValueString ().c_str (), getObjectTemplateName () ? getObjectTemplateName () : "null", attached->getNetworkId ().getValueString ().c_str (), attached, attached->getObjectTemplateName () ? attached->getObjectTemplateName () : "null", attached->getDebugName())); + attached->detachFromObject(DF_parent); + } + } + } + } + + m_inWorld = false; +} + +// ---------------------------------------------------------------------- + +void Object::addDpvsObject(DPVS::Object *dpvsObject) +{ + NOT_NULL(dpvsObject); + if (!m_dpvsObjects) + m_dpvsObjects = newDpvsObjects(); + + DpvsObjects::iterator i = std::find(m_dpvsObjects->begin(), m_dpvsObjects->end(), dpvsObject); + + if (i != m_dpvsObjects->end()) + { + DEBUG_FATAL(true, ("Object::addDpvsObject() Adding duplicate DPVS object [0x%08x] to Object %s", dpvsObject, getDebugInformation().c_str())); + return; + } + + m_dpvsObjects->push_back(dpvsObject); + + if (ms_inWorldAddDpvsObjectHookFunction && isInWorld()) + ms_inWorldAddDpvsObjectHookFunction(this, dpvsObject); +} + +// ---------------------------------------------------------------------- + +void Object::removeDpvsObject(DPVS::Object *dpvsObject) +{ + NOT_NULL(dpvsObject); + NOT_NULL(m_dpvsObjects); + + DpvsObjects::iterator i = std::find(m_dpvsObjects->begin(), m_dpvsObjects->end(), dpvsObject); + + if (i == m_dpvsObjects->end()) + { + DEBUG_FATAL(true, ("Object::removeDpvsObject() Removing unknown DPVS object [0x%08x] from Object %s", dpvsObject, getDebugInformation().c_str())); + return; + } + + *i = m_dpvsObjects->back(); + m_dpvsObjects->pop_back(); + + if (ms_inWorldRemoveDpvsObjectHookFunction && isInWorld()) + ms_inWorldRemoveDpvsObjectHookFunction(dpvsObject); +} + +// ---------------------------------------------------------------------- + +void Object::positionChanged(bool dueToParentChange, const Vector &oldPosition) +{ +#ifdef _DEBUG + IGNORE_RETURN(getTransform_o2p().validate()); + IGNORE_RETURN(getTransform_o2w().validate()); +#endif + + setObjectToWorldDirty(true); + + if (m_inWorld) + { + validatePosition(*this, getPosition_p()); + + m_notificationList->positionChanged(*this, dueToParentChange, oldPosition); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects::iterator end = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != end; ++i) + (*i)->positionChanged(true, (*i)->getPosition_p()); + } + } +} + +// ---------------------------------------------------------------------- + +void Object::rotationChanged(bool dueToParentChange) +{ +#ifdef _DEBUG + IGNORE_RETURN(getTransform_o2p().validate()); + IGNORE_RETURN(getTransform_o2w().validate()); +#endif + + setObjectToWorldDirty(true); + + if (m_inWorld) + { + m_notificationList->rotationChanged(*this, dueToParentChange); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects::iterator end = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != end; ++i) + (*i)->rotationChanged(true); + } + } +} + +// ---------------------------------------------------------------------- + +void Object::positionAndRotationChanged(bool dueToParentChange, const Vector &oldPosition) +{ +#ifdef _DEBUG + IGNORE_RETURN(getTransform_o2p().validate()); + IGNORE_RETURN(getTransform_o2w().validate()); +#endif + + setObjectToWorldDirty(true); + + if (m_inWorld) + { + validatePosition(*this, getPosition_p()); + + m_notificationList->positionAndRotationChanged(*this, dueToParentChange, oldPosition); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects::iterator end = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != end; ++i) + (*i)->positionAndRotationChanged(true, (*i)->getPosition_p()); + } + } +} + +// ---------------------------------------------------------------------- + +void Object::cellChanged(bool dueToParentChange) +{ + setObjectToWorldDirty(true); + + if (m_inWorld) + { + m_notificationList->cellChanged(*this, dueToParentChange); + + if (m_attachedObjects && !m_attachedObjects->empty()) + { + const AttachedObjects::iterator end = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != end; ++i) + (*i)->cellChanged(true); + } + } +} + +// ---------------------------------------------------------------------- + +void Object::extentChanged() +{ + if (m_inWorld) + m_notificationList->extentChanged(*this); +} + +// ---------------------------------------------------------------------- + +void Object::pobFixupComplete() +{ + if (m_inWorld) + m_notificationList->pobFixupComplete(*this); +} + +// ---------------------------------------------------------------------- +/** + * Set an active state for the object. + * + * Inactive objects will not render. + * + * @param newActive New active state for the object + */ + +void Object::setActive(bool newActive) +{ + m_active = newActive; +} + +// ---------------------------------------------------------------------- +/** + * Set a new dynamics for the object. + * + * The old dynamics pointer is simply overwritten. + * + * @param newDynamics New dynamics for the object + */ + +void Object::setDynamics(Dynamics *newDynamics) +{ + if (m_dynamics == newDynamics) + return; + + delete m_dynamics; + m_dynamics = newDynamics; +} + +// ---------------------------------------------------------------------- +/** + * Set a new controller for the object. + * + * The old controller pointer is simply overwritten. + * + * @param newController New controller for the object + */ + +void Object::setController(Controller *newController) +{ + if (m_controller == newController) + return; + + delete m_controller; + m_controller = newController; +} +// ---------------------------------------------------------------------- + +/** + * Determine if the object currently resides in the World cell + * @return true if in the world cell, else false + */ + +bool Object::isInWorldCell() const +{ + return getParentCell() == CellProperty::getWorldCellProperty(); +} + +// ---------------------------------------------------------------------- + +CellProperty *Object::getParentCell() const +{ + Property *cell = NULL; + + for (Object *o = const_cast(getAttachedTo()); o && !cell; o = o->getAttachedTo()) + cell = o->getCellProperty(); + + if (!cell) + return CellProperty::getWorldCellProperty(); + + return safe_cast(cell); +} + +// ---------------------------------------------------------------------- + +void Object::setParentCell(CellProperty *cellProperty) +{ + NOT_NULL(cellProperty); + + // if we are already in that cell, don't do anything. + if (getParentCell() == cellProperty) + return; + +#if 0 + DEBUG_FATAL(isChildObject(), ("Object::setParentCell called on child object [id=%s template=%s] with parent object [id=%s template=%s]", getNetworkId().getValueString().c_str(), getObjectTemplateName(), m_attachedToObject->getNetworkId().getValueString().c_str(), m_attachedToObject->getObjectTemplateName())); +#endif + + // if we were in another cell, detach us. This will leave out object in world space. + if (!isInWorldCell()) + detachFromObject(DF_world); + + // we are now relative to the new cell + if (cellProperty != CellProperty::getWorldCellProperty()) + attachToObject_w(&cellProperty->getOwner(), false); + + // issue a cell notification change + cellChanged(false); +} + +// ---------------------------------------------------------------------- +/** + * Get the object-to-world transformation for this object. + * + * @return Const reference to the object-to-world transform for this object + */ + +const Transform &Object::getTransform_o2w() const +{ +#if PROFILE_GETTRANSFORM_O2W == 1 + ++ms_totalCalls; +#endif + + if (m_attachedToObject) + { +#if PROFILE_GETTRANSFORM_O2W == 1 + ++ms_totalAttachedCalls; +#endif + +#if ENABLE_OBJECTTOWORLDDIRTY == 1 + if (m_objectToWorldDirty) +#endif + { +#if PROFILE_GETTRANSFORM_O2W == 1 + ++ms_totalAttachedDirtyCalls; +#endif + + m_objectToWorld->multiply(m_attachedToObject->getTransform_o2w(), m_objectToParent); + setObjectToWorldDirty(false); + } + + return *m_objectToWorld; + } + + return m_objectToParent; +} + +// ---------------------------------------------------------------------- + +void Object::setTransform_o2w(const Transform &objectToWorld) +{ + CellProperty const * cell = getParentCell(); + + if(cell == CellProperty::getWorldCellProperty()) + { + setTransform_o2p(objectToWorld); + return; + } + + Transform const & cellToWorld = cell->getOwner().getTransform_o2w(); + + Transform worldToCell; + + worldToCell.invert(cellToWorld); + + Transform objectToCell; + + objectToCell.multiply(worldToCell,objectToWorld); + + setTransform_o2p(objectToCell); +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance-to-parent transformation for this object. + * + * @return Const reference to the object-to-parent transform for this object + */ + +void Object::setTransform_a2w(const Transform &appearanceToWorld) const +{ + if (!m_appearance) + { + Appearance *dummyAppearance = new Appearance(0); + const_cast(this)->setAppearance(dummyAppearance); + } + + m_appearance->setTransform_w(appearanceToWorld); +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance-to-parent transformation for this object. + * + * @return Const reference to the object-to-parent transform for this object + */ + +const Transform &Object::getTransform_a2w() const +{ + if (!m_appearance) + { + Appearance *dummyAppearance = new Appearance(0); + const_cast(this)->setAppearance(dummyAppearance); + } + + return m_appearance->getTransform_w(); +} + +// ---------------------------------------------------------------------- + +const Transform Object::getTransform_o2c() const +{ + Transform result = getTransform_o2p(); + + for (const Object *o = getAttachedTo(); o && !o->getCellProperty(); o = o->getAttachedTo()) + result.multiply(o->getTransform_o2p(), result); + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Set a new Appearance for the object. + * + * This routine will delete the old appearance and assign the specified + * appearance. + * + * @param newAppearance New appearance for the object + */ + +void Object::setAppearance(Appearance *newAppearance) +{ + if (m_appearance == newAppearance) + return; + + + if (m_appearance) // delete the old appearance + { + // DBE - Copy the transform from the old appearance to the new one. + // This was added to mimic the behavior of when the appearance-to-world + // transform was stored in Object instead of Appearance. + if (newAppearance) + { + newAppearance->setTransform_w(m_appearance->getTransform_w()); + } + + if (isInWorld()) + { + m_appearance->removeFromWorld(); + } + delete m_appearance; + } + else + { + // DBE - Initialize the transform of the new appearance to our object-to-world + // transform. This was added to mimic the behavior of when the appearance-to-world + // transform was stored in Object instead of Appearance. + newAppearance->setTransform_w(getTransform_o2w()); + } + + // start using the new appearance + m_appearance = newAppearance; + + if (m_appearance) + { + m_appearance->setOwner(this); + m_appearance->setScale(m_scale); + + if (isInWorld()) + { + m_appearance->addToWorld(); + } + } + + m_defaultAppearance = m_appearance; + + +} + +// ---------------------------------------------------------------------- +/** + * Steal the Appearance from this object. + * + * This routine will return the current appearance of this object, and + * then reset its appearance to NULL. + * + * @return The current appearance of this object + */ + +Appearance *Object::stealAppearance(void) +{ + Appearance *oldAppearance = m_appearance; + + if(m_appearance == m_defaultAppearance) + m_defaultAppearance = NULL; + else if (m_appearance == m_alternateAppearance) + m_alternateAppearance = NULL; + + m_appearance = NULL; + + if (oldAppearance) + { + if (isInWorld()) + oldAppearance->removeFromWorld(); + + oldAppearance->setOwner(NULL); + } + + return oldAppearance; +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance's sphere's center. + * + * If the appearance doesn't exist, it returns the position of the object. + */ + +const Vector &Object::getAppearanceSphereCenter(void) const +{ + if (m_appearance) + return m_appearance->getSphere().getCenter(); + else + return Vector::zero; +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance's sphere's radius. + */ + +real Object::getAppearanceSphereRadius(void) const +{ + if(!m_appearance) + return 0; + return m_appearance->getSphere().getRadius(); +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance's sphere's center in world space. + * + * If the object does not have an appearance, this routine will return + * the same value as getPosition_w(), the object's world position. + */ + +const Vector Object::getAppearanceSphereCenter_w(void) const +{ + if (m_appearance) + return rotateTranslate_o2w(getAppearanceSphereCenter()); + else + return getPosition_w(); +} + +// ---------------------------------------------------------------------- +/** + * Alter the object specifying the amount of time that has passed. + * + * If the object is active, and has a Controller, the Controller's alter() routine will + * be called. + * + * If the object is active, and has an Appearance, the Appearances's alter() routine will + * be called. + * + * If this object is active, it will call alter() for all its child objects, + * + * @param time Number of elapsed seconds + */ + +float Object::alter(float time) +{ + PROFILER_AUTO_BLOCK_DEFINE("Object::alter"); + + DEBUG_FATAL(!isInitialized(), ("Alter called on uninitialized object:pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); + + if (m_kill) + return AlterResult::cms_kill; + + // Allow Object components to dictate whether they need an alter. + float alterResult = AlterResult::cms_keepNoAlter; + float appearanceAlterResult = AlterResult::cms_keepNoAlter; + float controllerAlterResult = AlterResult::cms_keepNoAlter; + float dynamicsAlterResult = AlterResult::cms_keepNoAlter; + float childrenAlterResult = AlterResult::cms_keepNoAlter; + + if (m_active) + { + // Note: characters assume appearances get an alter() prior to the controller getting an alter() + if (m_appearance) + { + appearanceAlterResult = m_appearance->alter(time); + AlterResult::incorporateAlterResult(alterResult, appearanceAlterResult); + } + + if (m_controller) + { + controllerAlterResult = m_controller->alter(time); + AlterResult::incorporateAlterResult(alterResult, controllerAlterResult); + } + + if (m_dynamics) + { + dynamicsAlterResult = m_dynamics->alter(time); + AlterResult::incorporateAlterResult(alterResult, dynamicsAlterResult); + } + + if (ms_objectsAlterChildrenAndContents) + { + // alter all the child objects + if (m_attachedObjects) + { + //-- note: children may not remove other children + int size = static_cast(m_attachedObjects->size ()); + + for (int i = 0; i < size;) + { + Object * const thisChild = (*m_attachedObjects)[static_cast(i)]; + NOT_NULL (thisChild); + + // handle child objects wanting to die + if (thisChild->isChildObject()) + { + if (thisChild->isInitialized()) + { + AlterScheduler::setMostRecentAlterTime(*thisChild); + float const childAlterResult = thisChild->alter(time); + if (childAlterResult == AlterResult::cms_kill) //lint !e777 // testing floats for equality // This is okay, we use constants for both set and test. + { + delete thisChild; + --size; + } + else + { + ++i; + AlterResult::incorporateAlterResult(childrenAlterResult, childAlterResult); + } + } + else + { + DEBUG_WARNING(true, ("Alter was about to be called on uninitialized child object [id=%s template=%s] with parent object [id=%s template=%s], skipping child alter", thisChild->getNetworkId().getValueString().c_str(), thisChild->getObjectTemplateName(), getNetworkId().getValueString().c_str(), getObjectTemplateName())); + ++i; + } + } + else + ++i; + } + + AlterResult::incorporateAlterResult(alterResult, childrenAlterResult); + } + + // alter all the contained objects + if (m_containerProperty) + m_containerProperty->alter(time); + } + } + +#ifdef _DEBUG + AlterScheduler::countObjectAlter(); + if (AlterScheduler::reportObjectAlters()) + { + char const * appearanceType = m_appearance ? typeid(*m_appearance).name() : "none"; + char const * controllerType = m_controller ? typeid(*m_controller).name() : "none"; + char const * dynamicsType = m_dynamics ? typeid(*m_dynamics).name() : "none"; + AlterScheduler::reportObjectAlter(this, appearanceType, appearanceAlterResult, controllerType, controllerAlterResult, dynamicsType, dynamicsAlterResult, childrenAlterResult, alterResult); + } +#endif + + // @todo fix this up to return what's appropriate for the state of this instance. + return alterResult; +} + +// ---------------------------------------------------------------------- +/** + * Conclude the object specifying the amount of time that has passed. + * + * If the object is active, and has a Controller, the Controller's conclude() routine will + * be called. + * + * If this object is active, it will call conclude() for all its child objects, + * + * @param time Number of elapsed seconds + */ + +void Object::conclude() +{ + if (isActive()) + { + if (m_controller) + m_controller->conclude(); + + // conclude all the child objects + if (m_attachedObjects) + { + const AttachedObjects::iterator end = m_attachedObjects->end(); + for (AttachedObjects::iterator i = m_attachedObjects->begin(); i != end; ++i) + if ((*i)->isChildObject()) + (*i)->conclude (); + } + } +} + +// ---------------------------------------------------------------------- + +int Object::getNumberOfAttachedObjects() const +{ + if (!m_attachedObjects) + return 0; + + return static_cast(m_attachedObjects->size()); +} + +// ---------------------------------------------------------------------- + +Object * Object::getAttachedObject(int const attachedObjectIndex) +{ + NOT_NULL(m_attachedObjects); + DEBUG_FATAL(attachedObjectIndex < 0 || attachedObjectIndex >= getNumberOfAttachedObjects(), ("attached object index out of range %d/%d", attachedObjectIndex, getNumberOfAttachedObjects())); + + Object * const attached = (*m_attachedObjects)[static_cast(attachedObjectIndex)]; + NOT_NULL (attached); + return attached; +} + +// ---------------------------------------------------------------------- + +Object const * Object::getAttachedObject(int const attachedObjectIndex) const +{ + NOT_NULL(m_attachedObjects); + DEBUG_FATAL(attachedObjectIndex < 0 || attachedObjectIndex >= getNumberOfAttachedObjects(), ("attached object index out of range %d/%d", attachedObjectIndex, getNumberOfAttachedObjects())); + + Object const * const attached = (*m_attachedObjects)[static_cast(attachedObjectIndex)]; + NOT_NULL (attached); + return attached; +} + +// ---------------------------------------------------------------------- +/** + * Get the number of child objects of this object. + * + * This routine walks a linked list of the objects to count the number + * of them. If you only need to know if the Object has child objects, + * call the more efficient hasChildObjects() routine instead. + * + * @return The number of child objects of this object + * @see Object::hasChildObjects() + */ + +int Object::getNumberOfChildObjects(void) const +{ + // todo @portal: make this reflect only child objects, not attached objects + if (!m_attachedObjects) + return 0; + + return static_cast (m_attachedObjects->size()); +} + +// ---------------------------------------------------------------------- +/** + * Get the specified child object. + * + * If the childObjectIndex is out of range, this routine will call Fatal + * in debug compiles. + * + * @param childObjectIndex Index of the child object to retrieve + * @return Pointer to the child object + */ + +Object *Object::getChildObject(int childObjectIndex) +{ + // todo @portal: make this reflect only child objects, not attached objects + + NOT_NULL(m_attachedObjects); + DEBUG_FATAL(childObjectIndex < 0 || childObjectIndex >= getNumberOfChildObjects(), ("child object index out of range %d/%d", childObjectIndex, getNumberOfChildObjects())); + + Object *child = (*m_attachedObjects) [static_cast (childObjectIndex)]; + NOT_NULL (child); + return child; +} + +// ---------------------------------------------------------------------- +/** + * Get the specified child object. + * + * If the childObjecIndex is out of range, this routine will call Fatal + * in debug compiles. + * + * @param childObjectIndex Index of the child object to retrieve + * @return Pointer to the child object + */ + +const Object *Object::getChildObject(int childObjectIndex) const +{ + // todo @portal: make this reflect only child objects, not attached objects + + NOT_NULL(m_attachedObjects); + DEBUG_FATAL(childObjectIndex < 0 || childObjectIndex >= getNumberOfChildObjects(), ("child object index out of range %d/%d", childObjectIndex, getNumberOfChildObjects())); + + const Object *child = (*m_attachedObjects) [static_cast (childObjectIndex)]; + NOT_NULL (child); + return child; +} + +// ---------------------------------------------------------------------- + +void Object::attachToObject_p(Object * const object, bool const asChildObject) +{ + NOT_NULL(object); + DEBUG_FATAL(m_childObject, ("Object::attachToObject_p: object %s already is a child object", getDebugInformation(true).c_str())); + DEBUG_FATAL(m_attachedToObject, ("Object::attachToObject_p: object %s already is relative to another object", getDebugInformation(true).c_str())); + DEBUG_FATAL(this == object, ("attempting to attach to self")); + + // If the child object is already attached to an object, detach it. + if (m_attachedToObject) + detachFromObject(DF_none); + + // put this on the list of attached objects + if (!object->m_attachedObjects) + object->m_attachedObjects = newAttachedObjects(); + object->m_attachedObjects->push_back(this); + + // remove the object from the world if its being added as a child + // and is currently in the world. This must happen before the m_childObject + // flag is set so that the worlds don't erroneously optimize out necessary + // operations by looking at the isChildObject() method. This issue happened + // with removing objects from the ClientWorld sphere trees. + if (asChildObject && isInWorld()) + removeFromWorld(); + + // every child should know its parent + m_attachedToObject = object; + m_childObject = asChildObject; + + // create a new objectToWorld transform for the child + m_objectToWorld = newLocalTransform(); + setObjectToWorldDirty(true); + + if (asChildObject) + { + // add the child to the world if the parent is in the world. + if (object->isInWorld()) + addToWorld(); + + // if parent objects alter their children, ensure the new child + // object is not in the alter scheduler. + if (ms_objectsAlterChildrenAndContents) + IGNORE_RETURN(AlterScheduler::removeObject(*this)); + } + + //-- always schedule an object for alter next frame if it has received a new child object + if (World::isInstalled() && World::existsInWorld(getRootParent())) + scheduleForAlter(); +} + +// ---------------------------------------------------------------------- + +void Object::attachToObject_w(Object *object, bool asChildObject) +{ +#ifdef _DEBUG + IGNORE_RETURN(m_objectToParent.validate()); +#endif + // calculate frame and position in the master's space + const Vector i = object->rotate_w2o(getObjectFrameI_w()); + const Vector j = object->rotate_w2o(getObjectFrameJ_w()); + const Vector k = object->rotate_w2o(getObjectFrameK_w()); + const Vector p = object->rotateTranslate_w2o(getPosition_w()); + + // set the transform of the child object + m_objectToParent.setLocalFrameIJK_p(i, j, k); + m_objectToParent.setPosition_p(p); + reorthonormalize(); + + // now do the attach in master space + attachToObject_p(object, asChildObject); +#ifdef _DEBUG + IGNORE_RETURN(m_objectToParent.validate()); +#endif + +} + +// ---------------------------------------------------------------------- +/** + * Detach an object from its master. + * + * Removal of an attached object causes the last attached object to move + * into its place in the vector. Therefore, attached object removal causes + * the order of attached objects to change. + */ + +void Object::detachFromObject(DetachFlags const detachFlags) +{ + NOT_NULL(m_attachedToObject); +#ifdef _DEBUG + IGNORE_RETURN(m_objectToParent.validate()); +#endif + + // leave the child object where it was in the same cell + bool const toParentCell = (detachFlags == DF_parent); + bool const noCell = (detachFlags == DF_none); + + CellProperty * const cellProperty = noCell ? 0 : (toParentCell ? getParentCell() : CellProperty::getWorldCellProperty()); + bool const shouldAttach = (!toParentCell || noCell) ? false : m_attachedToObject != &cellProperty->getOwner(); + m_objectToParent = shouldAttach ? getTransform_o2c() : getTransform_o2w(); + deleteLocalTransform(m_objectToWorld); + m_objectToWorld = NULL; + setObjectToWorldDirty(true); + + // remove from the attached objects list + AttachedObjects *attachedObjects = m_attachedToObject->m_attachedObjects; + const AttachedObjects::iterator i = std::find(attachedObjects->begin(), attachedObjects->end(), this); + DEBUG_FATAL(i == attachedObjects->end(), ("attached object was not found in parent")); + *i = attachedObjects->back(); + attachedObjects->pop_back(); + + // set as unattached + m_attachedToObject = NULL; + + bool const wasChildObject = isChildObject(); + bool const wasInWorld = isInWorld(); + if (wasChildObject && wasInWorld) + removeFromWorld(); + + m_childObject = false; + + if (wasChildObject && wasInWorld) + addToWorld(); + +#ifdef _DEBUG + IGNORE_RETURN(m_objectToParent.validate()); +#endif + + if (shouldAttach) + setParentCell(cellProperty); +} + +// ---------------------------------------------------------------------- +/** + * Add a new child object to the end of the child object list. + * + * This routine will append the new child object to the list of child + * objects. + * + * @param newChildObject New child object + */ + +void Object::addChildObject_o(Object * const newChildObject) +{ + DEBUG_FATAL(!ms_objectsAlterChildrenAndContents, ("Only the client should add child objects.")); + newChildObject->attachToObject_p(this, true); +} + +// ---------------------------------------------------------------------- +/** + * Add a new child object to the end of the child object list. + * + * This routine will append the new child object to the list of child + * objects. + * + * @param newChildObject New child object + */ + +void Object::addChildObject_p(Object * const newChildObject) +{ + // calculate frame and position in this object's space + Vector p = rotateTranslate_p2o(newChildObject->getPosition_p()); + Vector i = rotate_p2o(newChildObject->getObjectFrameI_p()); + Vector j = rotate_p2o(newChildObject->getObjectFrameJ_p()); + Vector k = rotate_p2o(newChildObject->getObjectFrameK_p()); + + // set the transform of the child object + newChildObject->setTransformIJK_o2p(i, j, k); + newChildObject->setPosition_p(p); + newChildObject->reorthonormalize(); + + // add this object as a child object + addChildObject_o(newChildObject); +} + +// ---------------------------------------------------------------------- +/** + * Remove a child object from this object. + * + * If the specified child object is not a child object of this object, + * this routine will call Fatal() in Debug compiles. + * + * The child object will be removed, and greater child objects will shift + * down one index position. + * + * @param childObjectToRemove The child object to remove + */ + +void Object::removeChildObject(Object * childObjectToRemove, DetachFlags detachFlags) const +{ + DEBUG_FATAL(!childObjectToRemove || (childObjectToRemove->getAttachedTo() != this), ("Removing a child that is not attached to this object.")); + childObjectToRemove->detachFromObject(detachFlags); +} + +// ---------------------------------------------------------------------- +/** + * Get the object at the top level of the object hierarchy + * + * @return the object at the top of the hierarchy or the current object if the object is at the top of the hierarchy + * @todo don't make this routine recursive + */ + +Object *Object::getRootParent(void) +{ + DEBUG_FATAL(m_childObject && m_attachedToObject == NULL, ("am a child but attached to is NULL")); + return m_childObject ? NON_NULL(m_attachedToObject)->getRootParent() : this; +} + +// ---------------------------------------------------------------------- +/** + * Get the object at the top level of the object hierarchy + * + * @return the object at the top of the hierarchy or the current object if the object is at the top of the hierarchy + * @todo don't make this routine recursive + */ + +const Object *Object::getRootParent(void) const +{ + DEBUG_FATAL(m_childObject && m_attachedToObject == NULL, ("am a child but attached to is NULL")); + return m_childObject ? NON_NULL(m_attachedToObject)->getRootParent() : this; +} + +// ---------------------------------------------------------------------- +/** + * Move the object in it's parent space. + * + * This routine moves the object in it's parent space, or the world space if + * the object has no parent. Therefore, moving along the Z axis will move the + * object forward along the Z-axis of it's parent space, not forward in the + * direction in which it is pointed. + * + * @param vector Offset to move in parent space + * @see Object::move_o() + */ + +void Object::move_p(const Vector &vector) +{ + if (vector != Vector::zero) + { + const Vector oldPosition = getPosition_p(); + m_objectToParent.move_p(vector); + positionChanged(false, oldPosition); + } +} + +// ---------------------------------------------------------------------- + +void Object::setRegionOfInfluenceEnabled(bool enabled) const +{ + UNREF(enabled); +} + +// ---------------------------------------------------------------------- +/** + * Called after the specified object has its containedByProperty changed + * + * This default implementation does nothing. + * + * Each object is assumed to have no more than one container associated + * with it; therefore, it is unambiguous which container is under + * consideration for this object. + * + * @param oldValue The container that used to hold this object + * @param newValue The container that now holds this object. + */ + + +void Object::containedByModified(const NetworkId & oldValue, const NetworkId & newValue,bool isLocal) +{ + UNREF (oldValue); + UNREF (newValue); + UNREF (isLocal); +} + +// ---------------------------------------------------------------------- +/** + * Called after the specified object has its slotted arrangement changed + * + * This default implementation does nothing. + * + * Each object is assumed to have no more than one container associated + * with it; therefore, it is unambiguous which container is under + * consideration for this object. + * + * @param oldValue The old arrangement + * @param newValue The new arrangement + */ + +void Object::arrangementModified(int oldValue, int newValue, bool isLocal) +{ + UNREF (oldValue); + UNREF (newValue); + UNREF (isLocal); +} + +// ---------------------------------------------------------------------- +/** + * Set the scale for this object. + * + * @param scale New scale for this object + */ + +void Object::setScale(const Vector &scale) +{ + m_scale = scale; + if (m_appearance) + m_appearance->setScale(scale); + + if (isInWorld()) + extentChanged(); +} + +// ---------------------------------------------------------------------- + +void Object::setRecursiveScale(Vector const & scale) +{ + setScale(scale); + int const numberOfChildObjects = getNumberOfChildObjects(); + for (int i = 0; i < numberOfChildObjects; ++i) + { + Object * const child = getChildObject(i); + if (child != 0) + { + child->setRecursiveScale(scale); + } + } +} + +//----------------------------------------------------------------------- + +Controller* Object::stealController(void) +{ + Controller* returnValue = m_controller; + m_controller = NULL; + return returnValue; +} + +// ---------------------------------------------------------------------- +/** + * Transform sphere from the world frame to the object's frame. + * + * @param sphere Vector to rotate and translate from world space into object space + * @return The source world-space sphere transformed into object space + */ + +const Sphere Object::rotateTranslate_o2w(const Sphere &sphere) const +{ + return Sphere(getTransform_o2w().rotateTranslate_l2p(sphere.getCenter()), sphere.getRadius()); +} + +// ---------------------------------------------------------------------- +/** + * Transform sphere from the world frame to the object's frame. + * + * @param sphere Vector to rotate and translate from world space into object space + * @return The source world-space sphere transformed into object space + */ + +const Sphere Object::rotateTranslate_w2o(const Sphere &sphere) const +{ + return Sphere(getTransform_o2w().rotateTranslate_p2l(sphere.getCenter()), sphere.getRadius()); +} + +// ---------------------------------------------------------------------- +/** + * Determine if this object has child objects. + * + * @return True if the object has one or more child objects, otherwise false. + */ + +bool Object::hasChildObjects() const +{ + return (m_attachedObjects && !m_attachedObjects->empty()); +} + +// ====================================================================== + +const char *Object::getObjectTemplateName() const +{ + return m_objectTemplate ? m_objectTemplate->getName() : 0; +} + +// ---------------------------------------------------------------------- + +Tag Object::getObjectType() const +{ + return m_objectTemplate ? m_objectTemplate->getId() : 0; +} + +// ---------------------------------------------------------------------- + +void Object::setNetworkId(const NetworkId &networkId) +{ + NetworkIdManager::removeObject(*this); + m_networkId = networkId; + NetworkIdManager::addObject(*this); +} + +// ---------------------------------------------------------------------- + +void Object::kill() +{ + m_kill = true; +} + +// ---------------------------------------------------------------------- + +void Object::addProperty(Property &property) +{ + // Default is to add property only while not in world. + bool const allowWhileInWorld = false; + addProperty(property, allowWhileInWorld); +} + +// ---------------------------------------------------------------------- + +void Object::addProperty(Property &property, bool allowWhileInWorld) +{ + UNREF(allowWhileInWorld); + + PropertyId propertyId = property.getPropertyId(); + + bool const inWorldNow = isInWorld(); + DEBUG_FATAL(getProperty(propertyId),("Cannot add already existing property.")); + DEBUG_FATAL(inWorldNow && !allowWhileInWorld, ("Cannot add property to object already in the world.")); + m_propertyList->push_back(&property); + + if (propertyId == CellProperty::getClassPropertyId() || propertyId == PortalProperty::getClassPropertyId() || propertyId == SlottedContainer::getClassPropertyId() || propertyId == VolumeContainer::getClassPropertyId()) + { + DEBUG_FATAL(m_containerProperty, ("Object already has a container property")); + m_containerProperty = safe_cast(&property); + } + else + { + if (propertyId == ContainedByProperty::getClassPropertyId()) + { + DEBUG_FATAL(m_containedBy, ("Object already has a collision property")); + m_containedBy = safe_cast(&property); + } + else + if (propertyId == CollisionProperty::getClassPropertyId()) + { + DEBUG_FATAL(m_collisionProperty, ("Object already has a collision property")); + m_collisionProperty = safe_cast(&property); + } + } + + //-- If this object is already in the world, let the property know about it. + if (inWorldNow) + property.addToWorld(); + +} //lint !e1764 // (Info -- Reference parameter 'property' (line 1717) could be declared const ref) // No, we need a pointer to a non-const Property. + +// ---------------------------------------------------------------------- + +Property const *Object::getProperty(PropertyId const &id) const +{ + ++ms_propertySearchStatistics[id]; + ++ms_propertySearchesPerFrame; + + for (PropertyList::const_iterator i = m_propertyList->begin(); i != m_propertyList->end(); ++i) + if ((*i)->getPropertyId() == id) + return *i; + + return NULL; +} + +// ---------------------------------------------------------------------- + +Property *Object::getProperty(PropertyId const &id) +{ + ++ms_propertySearchStatistics[id]; + ++ms_propertySearchesPerFrame; + + for (PropertyList::const_iterator i = m_propertyList->begin(); i != m_propertyList->end(); ++i) + if ((*i)->getPropertyId() == id) + return *i; + + return NULL; +} + +// ---------------------------------------------------------------------- + +void Object::removeProperty(PropertyId const &id) +{ + PropertyList::iterator i = m_propertyList->begin(); + for (; i != m_propertyList->end(); ++i) + if ((*i)->getPropertyId() == id) + break; + + if (i != m_propertyList->end()) + { + IGNORE_RETURN(m_propertyList->erase(i)); + } + else + { + DEBUG_FATAL(true, ("property not found")); + return; + } + + if (id == CellProperty::getClassPropertyId() || id == PortalProperty::getClassPropertyId() || id == SlottedContainer::getClassPropertyId() || id == VolumeContainer::getClassPropertyId()) + m_containerProperty = NULL; + else + if (id == ContainedByProperty::getClassPropertyId()) + m_containedBy = NULL; + else + if (id == CollisionProperty::getClassPropertyId()) + m_collisionProperty = NULL; +} + +// ---------------------------------------------------------------------- + +void Object::lookAt_p (const Vector &position_p) +{ + lookAt_o(rotateTranslate_p2o (position_p)); +} + +// ---------------------------------------------------------------------- + +void Object::lookAt_p (const Vector &position_p, const Vector &j_p) +{ + Vector k = position_p - getPosition_p(); // fwd vector in parent space + if (!k.normalize()) + return; + Vector i = j_p.cross(k); + if (!i.normalize()) + return; + k = i.cross(j_p); + if (!k.normalize()) + return; + setTransformIJK_o2p(i, j_p, k); +} + +// ---------------------------------------------------------------------- + +void Object::lookAt_o (const Vector &position_o) +{ + yaw_o (position_o.theta()); + pitch_o (position_o.phi()); +} + +// ---------------------------------------------------------------------- + +void Object::lookAt_o (const Vector &position_o, const Vector &j_o) +{ + lookAt_p(rotateTranslate_o2p(position_o), rotate_o2p(j_o)); +} + +// ---------------------------------------------------------------------- +/** + * Sets the new appearance from the specified appearance path. + */ + +void Object::setAppearanceByName(char const *path) +{ + if (path != NULL) + { + if (TreeFile::exists(path)) + { + // Create the object's new appearance + + Appearance *appearance = AppearanceTemplateList::createAppearance(path); + + setAppearance(appearance); + } + else + { + DEBUG_WARNING(true, ("Object::setAppearanceByName() - Unable to change the object's appearance because the file does not exist: %s", path)); + } + } + else + { + DEBUG_WARNING(true, ("Object::setAppearanceByName() - NULL appearance path specified for object: %s", (getObjectTemplateName() == NULL) ? "" : getObjectTemplateName())); + } +} + +// ---------------------------------------------------------------------- + +char const * Object::getAppearanceTemplateName() const +{ + return m_appearance ? m_appearance->getAppearanceTemplateName() : 0; +} + +//---------------------------------------------------------------------- +/** +* Find the actual world position of any object, regardless of containment. +* +* Note we're trying to get a real world coordinate, so we'll stop looking +* at the parent the second we have an object that's in the world. +*/ + +const Vector Object::findPosition_w () const +{ + const Object * obj = this; + + const ContainedByProperty * cbp = getContainedByProperty (); + + for ( ; !obj->isInWorld() && cbp; ) + { + const Object * const parent = cbp->getContainedBy (); + + if (parent) + { + obj = parent; + cbp = obj->getContainedByProperty (); + } + else + break; + } + + return obj->getPosition_w (); +} + +// ---------------------------------------------------------------------- + +void Object::scheduleForAlter() +{ + if (ms_objectsAlterChildrenAndContents) + { + scheduleForAlter_scheduleTopmostWorldParent(); + } + else + { + DEBUG_FATAL(!isInitialized(), ("scheduleForAlter() called on uninitialized object %s", getDebugInformation().c_str())); + + AlterScheduler::submitForAlter(*this); + } +} + +// ---------------------------------------------------------------------- + +SlottedContainer * Object::getSlottedContainerProperty() +{ + Container *container = getContainerProperty(); + if (container && container->getPropertyId() == SlottedContainer::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +SlottedContainer const * Object::getSlottedContainerProperty() const +{ + Container const *container = getContainerProperty(); + if (container && container->getPropertyId() == SlottedContainer::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +VolumeContainer * Object::getVolumeContainerProperty() +{ + Container *container = getContainerProperty(); + if (container && container->getPropertyId() == VolumeContainer::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +VolumeContainer const * Object::getVolumeContainerProperty() const +{ + Container const *container = getContainerProperty(); + if (container && container->getPropertyId() == VolumeContainer::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +CellProperty * Object::getCellProperty() +{ + Container *container = getContainerProperty(); + if (container && container->getPropertyId() == CellProperty::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +CellProperty const * Object::getCellProperty() const +{ + Container const *container = getContainerProperty(); + if (container && container->getPropertyId() == CellProperty::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +PortalProperty * Object::getPortalProperty() +{ + Container *container = getContainerProperty(); + if (container && container->getPropertyId() == PortalProperty::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +PortalProperty const * Object::getPortalProperty() const +{ + Container const *container = getContainerProperty(); + if (container && container->getPropertyId() == PortalProperty::getClassPropertyId()) + return safe_cast(container); + return NULL; +} + +// ---------------------------------------------------------------------- + +SpatialSubdivisionHandle* Object::getSpatialSubdivisionHandle () +{ + return m_spatialSubdivisionHandle; +} + +// ---------------------------------------------------------------------- + +void Object::setSpatialSubdivisionHandle (SpatialSubdivisionHandle* const spatialSubdivisionHandle) +{ + m_spatialSubdivisionHandle = spatialSubdivisionHandle; +} + +// ---------------------------------------------------------------------- + +ClientObject * Object::asClientObject() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +ClientObject const * Object::asClientObject() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +ServerObject * Object::asServerObject() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +ServerObject const * Object::asServerObject() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +bool Object::hasScheduleData() const +{ + return (m_scheduleData != NULL); +} + +// ---------------------------------------------------------------------- + +void Object::createScheduleDataIfNecessary(ScheduleTime initialMostRecentAlterTime) +{ + if (!m_scheduleData) + { +#if OBJECT_SUPPORTS_DESTROYED_FLAG + // Do not let a destroyed object get handled by the alter scheduler. + FATAL(m_isDestroyed, ("createScheduleDataIfNecessary(): trying to add a destroyed object to the alter scheduler.")); +#endif + + m_scheduleData = new ScheduleData(initialMostRecentAlterTime); + AlterScheduler::initializeScheduleTimeMapIterator(*this); + } +} + +// ---------------------------------------------------------------------- + +Object::ScheduleTime Object::getMostRecentAlterTime() const +{ + DEBUG_FATAL(!m_scheduleData, ("Calling getMostRecentAlterTime() on an object that has no schedule data.")); + return m_scheduleData->getMostRecentAlterTime(); +} + +// ---------------------------------------------------------------------- + +void Object::setMostRecentAlterTime(ScheduleTime mostRecentAlterTime) +{ + DEBUG_FATAL(!m_scheduleData, ("Calling setMostRecentAlterTime() on an object that has no schedule data.")); + m_scheduleData->setMostRecentAlterTime(mostRecentAlterTime); +} + +// ---------------------------------------------------------------------- + +bool Object::isInAlterNextFrameList() const +{ + return (m_scheduleData == NULL) ? false : (m_scheduleData->getAlterNextFrameNext() != NULL) || (m_scheduleData->getAlterNextFramePrevious() != NULL); +} + +// ---------------------------------------------------------------------- + +void Object::insertIntoAlterNextFrameList(Object *afterThisObject) +{ + DEBUG_FATAL(!m_scheduleData, ("Calling insertIntoAlterNextFrameList() on an object that has no schedule data.")); + DEBUG_FATAL(isInAlterNextFrameList(), ("insertIntoAlterNextFrameList(): object id=[%s],template=[%s] already in AlterNextFrame list.", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + NOT_NULL(afterThisObject); + NOT_NULL(afterThisObject->m_scheduleData); + DEBUG_FATAL(afterThisObject->m_scheduleData->getAlterNextFrameNext() && !afterThisObject->m_scheduleData->getAlterNextFrameNext()->m_scheduleData, ("Non-NULL forward link does not have schedule data.")); + DEBUG_FATAL(afterThisObject->m_scheduleData->getAlterNextFrameNext() && (afterThisObject->m_scheduleData->getAlterNextFrameNext()->m_scheduleData->getAlterNextFramePrevious() != afterThisObject), ("List corruption: alter next frame.")); + + //-- Get new next and previous object for the list. + Object *newPrevious = afterThisObject; + Object *newNext = afterThisObject->m_scheduleData->getAlterNextFrameNext(); + + //-- Handle new previous link. + m_scheduleData->setAlterNextFramePrevious(newPrevious); + newPrevious->m_scheduleData->setAlterNextFrameNext(this); + + //-- Handle new next link. + m_scheduleData->setAlterNextFrameNext(newNext); + if (newNext) + newNext->m_scheduleData->setAlterNextFramePrevious(this); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(!AlterScheduler::findObjectInAlterNextFrameList(this), ("insertIntoAlterNextFrameList(): object should be in list but isn't: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +void Object::removeFromAlterNextFrameList() +{ + DEBUG_FATAL(!isInAlterNextFrameList(), ("Called Object::removeFromAlterNextFrameList() when not in the list.")); + NOT_NULL(m_scheduleData); + + //-- Get the next and previous for the list. + Object *newPrevious = m_scheduleData->getAlterNextFramePrevious(); + Object *newNext = m_scheduleData->getAlterNextFrameNext(); + + DEBUG_FATAL(newPrevious && !newPrevious->m_scheduleData, ("Previous node missing schedule data.")); + DEBUG_FATAL(newNext && !newNext->m_scheduleData, ("Next node missing schedule data.")); + + //-- Handle previous. + m_scheduleData->setAlterNextFramePrevious(NULL); + if (newPrevious) + newPrevious->m_scheduleData->setAlterNextFrameNext(newNext); + + + //-- Handle next. + m_scheduleData->setAlterNextFrameNext(NULL); + if (newNext) + newNext->m_scheduleData->setAlterNextFramePrevious(newPrevious); + + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(AlterScheduler::findObjectInAlterNextFrameList(this), ("removeFromAlterNextFrameList(): object shouldn't be in list but is: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +int Object::getAlterSchedulePhase() const +{ + DEBUG_FATAL(m_scheduleData == NULL, ("calling Object::getAlterSchedulePhase() when Object has no schedule data: id=[%s], template=[%s]", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + return m_scheduleData->getSchedulePhase(); +} + +// ---------------------------------------------------------------------- + +void Object::setAlterSchedulePhase(int schedulePhaseIndex) +{ + DEBUG_FATAL(m_scheduleData == NULL, ("calling Object::setAlterSchedulePhase() when Object has no schedule data: id=[%s], template=[%s]", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + m_scheduleData->setSchedulePhase(schedulePhaseIndex); +} + +// ---------------------------------------------------------------------- + +bool Object::isInAlterNowList() const +{ + return (m_scheduleData == NULL) ? false : (m_scheduleData->getAlterNowNext() != NULL) || (m_scheduleData->getAlterNowPrevious() != NULL); +} + +// ---------------------------------------------------------------------- + +void Object::insertIntoAlterNowList(Object *afterThisObject) +{ + DEBUG_FATAL(!m_scheduleData, ("Calling insertIntoAlterNowList() on an object that has no schedule data.")); + DEBUG_FATAL(isInAlterNowList(), ("insertIntoAlterNowList(): object id=[%s],template=[%s] already in AlterNow list.", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + NOT_NULL(afterThisObject); + NOT_NULL(afterThisObject->m_scheduleData); + DEBUG_FATAL(afterThisObject->m_scheduleData->getAlterNowNext() && !afterThisObject->m_scheduleData->getAlterNowNext()->m_scheduleData, ("Non-NULL forward link does not have schedule data.")); + DEBUG_FATAL(afterThisObject->m_scheduleData->getAlterNowNext() && (afterThisObject->m_scheduleData->getAlterNowNext()->m_scheduleData->getAlterNowPrevious() != afterThisObject), ("List corruption: alter now.")); + + //-- Get new next and previous object for the list. + Object *newPrevious = afterThisObject; + Object *newNext = afterThisObject->m_scheduleData->getAlterNowNext(); + + //-- Handle new previous link. + m_scheduleData->setAlterNowPrevious(newPrevious); + newPrevious->m_scheduleData->setAlterNowNext(this); + + //-- Handle new next link. + m_scheduleData->setAlterNowNext(newNext); + if (newNext) + newNext->m_scheduleData->setAlterNowPrevious(this); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(!AlterScheduler::findObjectInAlterNowList(this), ("insertIntoAlterNowList(): object should be in list but isn't: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +void Object::removeFromAlterNowList() +{ + DEBUG_FATAL(!isInAlterNowList(), ("Called Object::removeFromAlterNowList() when not in the list.")); + NOT_NULL(m_scheduleData); + + //-- Get the next and previous for the list. + Object *newPrevious = m_scheduleData->getAlterNowPrevious(); + Object *newNext = m_scheduleData->getAlterNowNext(); + + DEBUG_FATAL(newPrevious && !newPrevious->m_scheduleData, ("Previous node missing schedule data.")); + DEBUG_FATAL(newNext && !newNext->m_scheduleData, ("Next node missing schedule data.")); + + //-- Handle previous. + m_scheduleData->setAlterNowPrevious(NULL); + if (newPrevious) + newPrevious->m_scheduleData->setAlterNowNext(newNext); + + //-- Handle next. + m_scheduleData->setAlterNowNext(NULL); + if (newNext) + newNext->m_scheduleData->setAlterNowPrevious(newPrevious); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(AlterScheduler::findObjectInAlterNowList(this), ("removeFromAlterNowList(): object shouldn't be in list but is: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +bool Object::isInConcludeList() const +{ + return (m_scheduleData == NULL) ? false : (m_scheduleData->getConcludeNext() != NULL) || (m_scheduleData->getConcludePrevious() != NULL); +} + +// ---------------------------------------------------------------------- + +void Object::insertIntoConcludeList(Object *afterThisObject) +{ + DEBUG_FATAL(!m_scheduleData, ("Calling insertIntoConcludeList() on an object that has no schedule data.")); + DEBUG_FATAL(isInConcludeList(), ("insertIntoConcludeList(): object id=[%s],template=[%s] already in Conclude list.", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + NOT_NULL(afterThisObject); + NOT_NULL(afterThisObject->m_scheduleData); + DEBUG_FATAL(afterThisObject->m_scheduleData->getConcludeNext() && !afterThisObject->m_scheduleData->getConcludeNext()->m_scheduleData, ("Non-NULL forward link does not have schedule data.")); + DEBUG_FATAL(afterThisObject->m_scheduleData->getConcludeNext() && (afterThisObject->m_scheduleData->getConcludeNext()->m_scheduleData->getConcludePrevious() != afterThisObject), ("List corruption: alter now.")); + + //-- Get new next and previous object for the list. + Object *newPrevious = afterThisObject; + Object *newNext = afterThisObject->m_scheduleData->getConcludeNext(); + + //-- Handle new previous link. + m_scheduleData->setConcludePrevious(newPrevious); + newPrevious->m_scheduleData->setConcludeNext(this); + + //-- Handle new next link. + m_scheduleData->setConcludeNext(newNext); + if (newNext) + newNext->m_scheduleData->setConcludePrevious(this); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(!AlterScheduler::findObjectInConcludeList(this), ("insertIntoConcludeList(): object should be in list but isn't: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +void Object::removeFromConcludeList() +{ + DEBUG_FATAL(!isInConcludeList(), ("Called Object::removeFromConcludeList() when not in the list.")); + NOT_NULL(m_scheduleData); + + //-- Get the next and previous for the list. + Object *newPrevious = m_scheduleData->getConcludePrevious(); + Object *newNext = m_scheduleData->getConcludeNext(); + + DEBUG_FATAL(newPrevious && !newPrevious->m_scheduleData, ("Previous node missing schedule data.")); + DEBUG_FATAL(newNext && !newNext->m_scheduleData, ("Next node missing schedule data.")); + + //-- Handle previous. + m_scheduleData->setConcludePrevious(NULL); + if (newPrevious) + newPrevious->m_scheduleData->setConcludeNext(newNext); + + //-- Handle next. + m_scheduleData->setConcludeNext(NULL); + if (newNext) + newNext->m_scheduleData->setConcludePrevious(newPrevious); + +#if AS_USE_HARDCORE_CONTAINER_VALIDATION + //-- Post assertion. + DEBUG_FATAL(AlterScheduler::findObjectInConcludeList(this), ("removeFromConcludeList(): object shouldn't be in list but is: pointer=[%p],id=[%s],template=[%s].", this, getNetworkId().getValueString().c_str(), getObjectTemplateName())); +#endif +} + +// ---------------------------------------------------------------------- + +void *Object::getScheduleTimeMapIterator() +{ + DEBUG_FATAL(!m_scheduleData, ("getScheduleTimeMapIterator() called but this object doesn't have schedule data.")); + return &m_scheduleData->getScheduleTimeMapIterator(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getNextFromAlterNowList() +{ + DEBUG_FATAL(!m_scheduleData, ("getNextFromAlterNowList() called but this object doesn't have schedule data.")); + return m_scheduleData->getAlterNowNext(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getPreviousFromAlterNowList() +{ + DEBUG_FATAL(!m_scheduleData, ("getPreviousFromAlterNowList() called but this object doesn't have schedule data.")); + return m_scheduleData->getAlterNowPrevious(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getNextFromAlterNextFrameList() +{ + DEBUG_FATAL(!m_scheduleData, ("getNextFromAlterNextFrameList() called but this object doesn't have schedule data.")); + return m_scheduleData->getAlterNextFrameNext(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getPreviousFromAlterNextFrameList() +{ + DEBUG_FATAL(!m_scheduleData, ("getPreviousFromAlterNextFrameList() called but this object doesn't have schedule data.")); + return m_scheduleData->getAlterNextFramePrevious(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getNextFromConcludeList() +{ + DEBUG_FATAL(!m_scheduleData, ("getNextFromConcludeList() called but this object doesn't have schedule data.")); + return m_scheduleData->getConcludeNext(); +} + +// ---------------------------------------------------------------------- + +Object *Object::getPreviousFromConcludeList() +{ + DEBUG_FATAL(!m_scheduleData, ("getPreviousFromConcludeList() called but this object doesn't have schedule data.")); + return m_scheduleData->getConcludePrevious(); +} + +// ---------------------------------------------------------------------- + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + +void Object::setIsAltering(bool newIsAltering) +{ + DEBUG_FATAL((newIsAltering && m_isAltering) || (!newIsAltering && !m_isAltering), ("Object::setIsAltering(): setting same alter state, likely bad logic flow for object. old/new state is [%s].", m_isAltering ? "true" : "false")); + m_isAltering = newIsAltering; +} + +#endif + +// ---------------------------------------------------------------------- +/** + * Alter scheduler scheduleForAlter strategy that goes up the parent + * chain to the top-most object in the world for alter scheduling. + * + * Client-side objects adopt this strategy, including + * ClientObject and HardpointObject. Not all client-side objects + * derive from ClientObject, so we stick this strategy in the base + * Object class, override the virtual scheduleForAlter(), and forward + * that function to this one. + * + * More details: + * + * Ensure this Object instance gets an alter() call via the + * AlterScheduler the next time alter processing occurs. + * + * This function will ensure only the top-most object in the world is + * added to the AlterScheduler. We do this because those are the only + * objects that should receive an alter, as they propagate alter calls + * to their children and contained items. + * + * To find the top-most instance to alter given this instance, first + * we traverse the parent-child loop looking for the top-most parent. + * Then we traverse the container-contained hierarchy looking for the + * first Object that is in the world. The traversed object that meets + * the following conditions is put on the AlterScheduler: (1) does not have + * a parent object and (2) is not contained or is contained but is in the world. + */ +void Object::scheduleForAlter_scheduleTopmostWorldParent() +{ + Object *alterObject = this; + + do + { + //-- Traverse parent links until there is no more parent. + for (Object *parentObject = alterObject->getParent(); parentObject != NULL; parentObject = alterObject->getParent()) + alterObject = parentObject; + + //-- Traverse container until we're at a container object that is in the world. + if (!alterObject->isInWorld()) + { + //-- Use the first container parent that is in the world. + ContainedByProperty *containedByProperty = alterObject->getContainedByProperty(); + while (containedByProperty) + { + // Get the container object. + Object *const containerObject = containedByProperty->getContainedBy(); + if (!containerObject) + break; + else + { + alterObject = containerObject; + if (alterObject->isInWorld()) + { + // We're done searching. + containedByProperty = NULL; + } + else + { + // The container object is not in the world, so search for it's container. + containedByProperty = alterObject->getContainedByProperty(); + } + } + } + + //-- If we get here and the alterObject is not in the world, something seems wrong. + // This object needs to be altered but doesn't have a root-most object in the world. + // DEBUG_FATAL(!alterObject->isInWorld(), ("trying to schedule an alter for an object [%s] whose root-most container object [%s] isn't in the world!", getNetworkId().getValueString().c_str(), alterObject->getNetworkId().getValueString().c_str())); + } + + // New container might be a child object, make sure we test for a parent again. + // If a parent exists, we need to run through the loop again to find the parent object. + } while (alterObject->getParent() != NULL); + + NOT_NULL(alterObject); + if (alterObject->isInitialized()) + AlterScheduler::submitForAlter(*alterObject); +} + +// ---------------------------------------------------------------------- + +void Object::nullWatchers() +{ + m_watchedByList.nullWatchers(); +} + +// ---------------------------------------------------------------------- + +AxialBox const ObjectNamespace::getTangibleExtentInternal(Object const &obj) +{ + AxialBox result; + + //-- If this has an applicable appearance, the result begins with this + Appearance const * const appearance = obj.getAppearance(); + if (appearance) + result = appearance->getTangibleExtent(); + + //-- Iterate through all of the children and grow the result axial box + int const numberOfChildObjects = obj.getNumberOfChildObjects(); + for (int i = 0; i < numberOfChildObjects; ++i) + { + Object const * const childObject = obj.getChildObject(i); + if (!childObject || !childObject->isChildObject()) + continue; + + AxialBox const axialBox = getTangibleExtentInternal(*childObject); + + //-- Transform box from child space into parent space and grow result + if (!axialBox.isEmpty()) + for (int j = 0; j < 8; ++j) + result.add(childObject->getTransform_o2p().rotateTranslate_l2p(axialBox.getCorner(j))); + } + + return result; +} + +// ---------------------------------------------------------------------- + +AxialBox const Object::getTangibleExtent() const +{ + AxialBox result = getTangibleExtentInternal(*this); + + // Return a zero sized box at the appearance center if there is no other + // tangible extent. If there is no appearance this centers at the local + // origin. + if (result.isEmpty()) + result.add(getAppearanceSphereCenter()); + + return result; +} + +// ---------------------------------------------------------------------- + +bool Object::getUseAlterScheduler() const +{ + return m_useAlterScheduler; +} + +// ---------------------------------------------------------------------- + +void Object::setUseAlterScheduler(bool const useAlterScheduler) +{ + m_useAlterScheduler = useAlterScheduler; +} + +// ---------------------------------------------------------------------- + +void Object::setObjectToWorldDirty(bool const objectToWorldDirty) const +{ +#if ENABLE_OBJECTTOWORLDDIRTY == 1 + for (int i = 0; i < getNumberOfAttachedObjects(); ++i) + getAttachedObject(i)->setObjectToWorldDirty(true); +#endif + + m_objectToWorldDirty = objectToWorldDirty; +} + +// ---------------------------------------------------------------------- + +Sphere const Object::getCollisionSphereExtent_o() const +{ + Sphere sphere_o(Sphere::unit); + + CollisionProperty const * const collisionProperty = getCollisionProperty(); + + if (collisionProperty != 0) + { + sphere_o = collisionProperty->getBoundingSphere_l(); + } + else + { + sphere_o.setRadius(1.0f); + } + + return sphere_o; +} + +// ---------------------------------------------------------------------- + +Sphere const Object::getCollisionSphereExtent_w() const +{ + Sphere const sphere_o(getCollisionSphereExtent_o()); + Sphere sphere_w; + + sphere_w.setCenter(rotateTranslate_o2w(sphere_o.getCenter())); + sphere_w.setRadius(sphere_o.getRadius()); + + return sphere_w; +} + +// ---------------------------------------------------------------------- + +float Object::getDistanceBetweenCollisionSpheres_w(Object const & object) const +{ + float distance = 0.0f; + + if (&object != this) + { + Vector const & a_w = getPosition_w(); + Vector const & b_w = object.getPosition_w(); + + distance = a_w.magnitudeBetween(b_w); + distance -= getCollisionSphereExtent_o().getRadius(); + distance -= object.getCollisionSphereExtent_o().getRadius(); + distance = std::max(0.0f, distance); + } + + return distance; +} + +// ---------------------------------------------------------------------- + +void Object::getObjectInfo(std::map > & propertyMap) const +{ +/** + When adding a variable to this class, please add it here. Variable that aren't easily displayable are still listed, for tracking purposes. +*/ + +/** + Don't compile in production build because this maps human-readable values to data members and makes hacking easier +*/ +#if PRODUCTION == 0 + + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "InWorld", m_inWorld); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "Active", m_active); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "Kill", m_kill); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "Authoritative", m_authoritative); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ChildObject", m_childObject); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ObjectToWorldDirty", m_objectToWorldDirty); +#if OBJECT_SUPPORTS_DESTROYED_FLAG + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "IsDestroyed", m_isDestroyed); +#endif +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "IsAltering", m_isAltering); +#endif + if(getObjectTemplateName()) + { + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ObjectTemplateName", getObjectTemplateName()); + } + else + { + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ObjectTemplateName", "Unknown"); + } +//const NotificationList *m_notificationList; + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "DebugName", m_debugName); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "NetworkId", m_networkId.getValueString()); + if(m_objectTemplate) + { + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "AppearanceTemplateName", getAppearanceTemplateName()); + } + else + { + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "AppearanceTemplateName", "Unknown"); + } +//Controller *m_controller; +//Dynamics *m_dynamics; + + if(m_attachedToObject) + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "AttachedToObject", m_attachedToObject->getNetworkId().getValueString()); + else + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "AttachedToObject", ""); + +//AttachedObjects *m_attachedObjects; +//DpvsObjects *m_dpvsObjects; + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "Rotations", m_rotations); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "Scale", m_scale); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ObjectToParent", m_objectToParent); + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ObjectToWorld", m_objectToWorld); +//mutable WatchedByList m_watchedByList; +//Container *m_containerProperty; +//CollisionProperty *m_collisionProperty; +//SpatialSubdivisionHandle *m_spatialSubdivisionHandle; + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "UseAlterScheduler", m_useAlterScheduler); +//ScheduleData *m_scheduleData; + + if(m_containedBy) + DebugInfoManager::addProperty(propertyMap, ms_debugInfoSectionName, "ContainedBy", m_containedBy->getContainedByNetworkId().getValueString()); +#else + UNREF(propertyMap); +#endif +} + +// ---------------------------------------------------------------------- + +void Object::setAlternateAppearance(const char * path) +{ + + if(!path) + return; + + Appearance *alternateAppearance = NULL; + + if (TreeFile::exists(path)) + { + alternateAppearance = AppearanceTemplateList::createAppearance(path); + } + else + { + return; + } + + bool const instantlyApplyAppearance = isUsingAlternateAppearance(); + + if(instantlyApplyAppearance) + { + if(isInWorld() && m_appearance) + m_appearance->removeFromWorld(); + } + + if (m_alternateAppearance == alternateAppearance) + { + delete alternateAppearance; + return; + } + + + if (m_alternateAppearance) // delete the old appearance + { + // DBE - Copy the transform from the old appearance to the new one. + // This was added to mimic the behavior of when the appearance-to-world + // transform was stored in Object instead of Appearance. + if (alternateAppearance) + { + alternateAppearance->setTransform_w(m_alternateAppearance->getTransform_w()); + } + + delete m_alternateAppearance; + + m_alternateAppearance = NULL; + } + else + { + // DBE - Initialize the transform of the new appearance to our object-to-world + // transform. This was added to mimic the behavior of when the appearance-to-world + // transform was stored in Object instead of Appearance. + alternateAppearance->setTransform_w(getTransform_o2w()); + } + + // start using the new appearance + m_alternateAppearance = alternateAppearance; + + if(instantlyApplyAppearance) + { + m_alternateAppearance->setOwner(this); + m_alternateAppearance->setScale(m_scale); + + if (isInWorld()) + { + m_alternateAppearance->addToWorld(); + } + + m_appearance = m_alternateAppearance; + } + else + { + useAlternateAppearance(); + } + + DEBUG_REPORT_LOG(false, ("Successfully set the alternate appearance for [%s] to [%s]\n", getNetworkId().getValueString().c_str(), path)); +} + +// ---------------------------------------------------------------------- + +void Object::useAlternateAppearance() +{ + if(!m_alternateAppearance || m_alternateAppearance == m_appearance) + return; + + if(isInWorld()) + m_appearance->removeFromWorld(); + + m_alternateAppearance->setOwner(this); + m_alternateAppearance->setScale(m_scale); + + + if (isInWorld()) + { + m_alternateAppearance->addToWorld(); + } + + m_appearance = m_alternateAppearance; + + DEBUG_REPORT_LOG(false, ("Object [%s] changed to their alternate appearance.\n", getNetworkId().getValueString().c_str())); + +} + +// ---------------------------------------------------------------------- + +void Object::useDefaultAppearance() +{ + if(!m_defaultAppearance || m_defaultAppearance == m_appearance) + return; + + if(m_appearance) + m_appearance->removeFromWorld(); + + m_defaultAppearance->setOwner(this); + m_defaultAppearance->setScale(m_scale); + + if (isInWorld()) + { + m_defaultAppearance->addToWorld(); + } + + m_appearance = m_defaultAppearance; + + DEBUG_REPORT_LOG(false, ("Object [%s] changed to their default appearance.\n", getNetworkId().getValueString().c_str())); +} +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/Object.h b/engine/shared/library/sharedObject/src/shared/object/Object.h new file mode 100644 index 00000000..7ac8cfe1 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/Object.h @@ -0,0 +1,1367 @@ +// ====================================================================== +// +// Object.h +// copyright 1998 Bootprint Entertainment +// Copyright 2000-2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Object_H +#define INCLUDED_Object_H + +// ====================================================================== + +class AlterScheduler; +class Appearance; +class AxialBox; +class Camera; +class CellProperty; +class ClientObject; +class CollisionProperty; +class Controller; +class Container; +class ContainedByProperty; +class Dynamics; +class Iff; +class ObjectNotification; +class ObjectTemplate; +class PortalProperty; +class Property; +class ScheduleData; +class ServerObject; +class SlottedContainer; +class SpatialSubdivisionHandle; +class Sphere; +class MemoryBlockManager; +class VolumeContainer; +typedef uint32 PropertyId; + +namespace DPVS +{ + class Object; +}; + +#include "sharedFoundation/Tag.h" +#include "sharedFoundation/Watcher.h" +#include "sharedMath/Transform.h" +#include "sharedMath/Vector.h" +#include "sharedFoundation/NetworkId.h" + +// ====================================================================== + +#ifdef _DEBUG + +#define OBJECT_SUPPORTS_DESTROYED_FLAG 1 +#define OBJECT_SUPPORTS_IS_ALTERING_FLAG 1 + +#else + +#define OBJECT_SUPPORTS_DESTROYED_FLAG 1 +#define OBJECT_SUPPORTS_IS_ALTERING_FLAG 1 + +#endif + +// ====================================================================== + +// Base object class for all objects in the 3d system. +// +// Suffixes: +// A == appearance +// O == object +// P == parent +// W == world + +class Object +{ + friend class AlterScheduler; + +public: + + enum InitializeFlag + { + IF_clientOnly + }; + + enum DetachFlags + { + DF_none, // Do not attach to another cell. + DF_parent, // Attach to the parent's cell. + DF_world // Place the object into the world cell. + }; + + typedef stdvector::fwd DpvsObjects; + typedef uint64 ScheduleTime; + + class NotificationList; + class NotificationListManager; + +public: + + typedef void (*InWorldAddDpvsObjectHookFunction)(Object *object, DPVS::Object *dpvsObject); + typedef void (*InWorldRemoveDpvsObjectHookFunction)(DPVS::Object *dpvsObject); + typedef void (*LeakedDpvsObjectHookFunction)(DPVS::Object *dpvsObject); + + static void install(bool objectsAlterChildrenAndContents); + static void setDpvsObjectHookFunctions(InWorldAddDpvsObjectHookFunction alreadyInWorldAddDpvsObjectHookFunction, InWorldRemoveDpvsObjectHookFunction inWorldRemoveDpvsObjectHookFunction, LeakedDpvsObjectHookFunction leakedDpvsObjectHookFunction); + static void setDisallowObjectDelete(bool disallowObjectDelete); + static bool shouldObjectsAlterChildrenAndContents(); + +public: + + Object(); + Object(const ObjectTemplate *objectTemplate, InitializeFlag clientOnly); + Object(const ObjectTemplate *objectTemplate, const NetworkId &networkId); + virtual ~Object(); + + virtual bool isInitialized() const; + + bool isInWorld() const; + virtual void addToWorld(); + virtual void removeFromWorld(); + + bool hasNotification(const ObjectNotification ¬ification) const; + + // If allowWhenInWorld is true, the notification can be added to the object even if the object is already + // in the world. This could be a bad thing (since a notification usually expects to receive/ matched + // addToWorld/removeFromWorld pairs), but in certain cases it's required. Be careful when setting + // allowWhenInWorld to true. + + void addNotification(const ObjectNotification ¬ification, bool allowWhenInWorld = false); + void removeNotification(const ObjectNotification ¬ification, bool allowWhenInWorld = false); + + WatchedByList &getWatchedByList() const; + + virtual float alter(float time); + virtual void conclude(); + + bool getKill() const; + virtual void kill(); + + virtual void setRegionOfInfluenceEnabled(bool enabled) const; + + virtual ContainedByProperty* getContainedByProperty(); + virtual const ContainedByProperty* getContainedByProperty() const; + + //@todo these next 2 would be better implemented as notifications or messages. + virtual void containedByModified(const NetworkId & oldValue, const NetworkId & newValue,bool); + virtual void arrangementModified(int oldValue, int newValue,bool); + + const ObjectTemplate *getObjectTemplate() const; + const char *getObjectTemplateName() const; + Tag getObjectType() const; + + const char *getDebugName() const; + void setDebugName(const char *debugName); + std::string const getDebugInformation(bool includeParent = false) const; + + bool isActive() const; + virtual void setActive(bool active); + + bool isAuthoritative() const; + void setAuthoritative(bool authoritative); + + const NetworkId &getNetworkId() const; + void setNetworkId(const NetworkId &networkId); + + CellProperty *getParentCell() const; + virtual void setParentCell(CellProperty *cellProperty); + bool isInWorldCell() const; + + const Appearance *getAppearance() const; + Appearance *getAppearance(); + Appearance *stealAppearance(); + const Vector &getAppearanceSphereCenter() const; + const Vector getAppearanceSphereCenter_w() const; + real getAppearanceSphereRadius() const; + void setAppearance(Appearance *appearance); + void setAppearanceByName(char const *path); + char const * getAppearanceTemplateName() const; + + Sphere const getCollisionSphereExtent_o() const; + Sphere const getCollisionSphereExtent_w() const; + float getDistanceBetweenCollisionSpheres_w(Object const & object) const; + + void addDpvsObject(DPVS::Object *dpvsObject); + void removeDpvsObject(DPVS::Object *dpvsObject); + const DpvsObjects *getDpvsObjects() const; + + const Controller *getController() const; + Controller *getController(); + Controller *stealController(); + void setController(Controller *controller); + + const Dynamics *getDynamics() const; + Dynamics *getDynamics(); + Dynamics *stealDynamics(); + void setDynamics(Dynamics *dynamics); + + void attachToObject_p(Object *object, bool asChildObject); + void attachToObject_w(Object *object, bool asChildObject); + void detachFromObject(DetachFlags detachFlags); + + bool isChildObject() const; + bool hasChildObjects() const; + Object *getParent(); + const Object *getParent() const; + Object *getAttachedTo(); + const Object *getAttachedTo() const; + Object *getRootParent(); + const Object *getRootParent() const; + int getNumberOfAttachedObjects() const; + Object * getAttachedObject(int attachedObjectIndex); + Object const * getAttachedObject(int attachedObjectIndex) const; + int getNumberOfChildObjects() const; + Object *getChildObject(int childObjectIndex); + const Object *getChildObject(int childObjectIndex) const; + void addChildObject_o(Object *childObject); + void addChildObject_p(Object *childObject); + void removeChildObject(Object *childObjectToRemove, DetachFlags detachFlags) const; + + void addProperty(Property& property); + void addProperty(Property& property, bool allowWhileInWorld); + const Property *getProperty(const PropertyId& id) const; + Property *getProperty(const PropertyId& id); + void removeProperty(const PropertyId& id); + + const Vector &getScale() const; + void setScale(const Vector &scale); + // recursively scales this and all of it's children + // parent space locations of the children are _not_ scaled + void setRecursiveScale(Vector const & scale); + + const Transform &getTransform_o2p() const; + DLLEXPORT Transform const & getTransform_o2w() const; + const Transform getTransform_o2c() const; + const Transform &getTransform_p2w() const; + const Vector findPosition_w() const; + const Vector getPosition_w() const; + const Vector getPosition_c() const; + const Vector getPosition_p() const; + void setPosition_p(const Vector &position_p); + void setPosition_w(const Vector &position_w); + void setTransform_o2p(const Transform &objectToParentTransform); + void setTransform_o2w(const Transform &objectToWorldTransform); + void setTransformIJK_o2p(const Vector &i, const Vector &j, const Vector &k); + void setTransformKJ_o2p(const Vector &k, const Vector &j); + + const Transform &getTransform_a2w() const; + void setTransform_a2w(const Transform &appearanceToWorldTransform) const; + + void move_p(const Vector &vectorInParentSpace); + void move_o(const Vector &vectorInObjectSpace); + + void yaw_o(real radians); + void pitch_o(real radians); + void roll_o(real radians); + void resetRotate_o2p(); + void resetRotateTranslate_o2p(); + void lookAt_p(const Vector &position_p, const Vector& j_o); + void lookAt_p(const Vector &position_p); + void lookAt_o(const Vector &position_o, const Vector& j_o); + void lookAt_o(const Vector &position_o); + + const Vector getObjectFrameI_p() const; + const Vector getObjectFrameJ_p() const; + const Vector getObjectFrameK_p() const; + const Vector getObjectFrameI_w() const; + const Vector getObjectFrameJ_w() const; + const Vector getObjectFrameK_w() const; + + const Vector getParentFrameI_o() const; + const Vector getParentFrameJ_o() const; + const Vector getParentFrameK_o() const; + + const Vector rotate_o2p(const Vector &vectorToTransform) const; + const Vector rotateTranslate_o2p(const Vector &vectorToTransform) const; + const Vector rotate_p2o(const Vector &vectorToTransform) const; + const Vector rotateTranslate_p2o(const Vector &vectorToTransform) const; + const Vector rotate_p2w(const Vector &vectorToTransform) const; + const Vector rotateTranslate_p2w(const Vector &vectorToTransform) const; + const Vector rotate_w2p(const Vector &vectorToTransform) const; + const Vector rotateTranslate_w2p(const Vector &vectorToTransform) const; + + const Vector rotate_o2w(const Vector &vectorToTransform) const; + const Vector rotateTranslate_o2w(const Vector &vectorToTransform) const; + const Sphere rotateTranslate_o2w(const Sphere &sphereToTransform) const; + const Vector rotate_w2o(const Vector &vectorToTransform) const; + const Vector rotateTranslate_w2o(const Vector &vectorToTransform) const; + const Sphere rotateTranslate_w2o(const Sphere &sphereToTransform) const; + + virtual void scheduleForAlter(); + + Container * getContainerProperty(); + Container const * getContainerProperty() const; + SlottedContainer * getSlottedContainerProperty(); + SlottedContainer const * getSlottedContainerProperty() const; + VolumeContainer * getVolumeContainerProperty(); + VolumeContainer const * getVolumeContainerProperty() const; + CellProperty * getCellProperty(); + CellProperty const * getCellProperty() const; + PortalProperty * getPortalProperty(); + PortalProperty const * getPortalProperty() const; + + CollisionProperty * getCollisionProperty(); + CollisionProperty const * getCollisionProperty() const; + + SpatialSubdivisionHandle* getSpatialSubdivisionHandle (); + void setSpatialSubdivisionHandle (SpatialSubdivisionHandle* spatialSubdivisionHandle); + + virtual ClientObject * asClientObject(); + virtual ClientObject const * asClientObject() const; + virtual ServerObject * asServerObject(); + virtual ServerObject const * asServerObject() const; + +#if OBJECT_SUPPORTS_DESTROYED_FLAG + bool isDestroyed() const; +#endif + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + bool isAltering() const; +#endif + + void extentChanged(); + void pobFixupComplete(); + AxialBox const getTangibleExtent() const; + + bool getUseAlterScheduler() const; + void setUseAlterScheduler(bool const useAlterScheduler); + + virtual void getObjectInfo(stdmap::fwd >::fwd & propertyMap) const; + + bool getShouldBakeIntoMesh() const; + void setShouldBakeIntoMesh(bool bake); + + void setAlternateAppearance(const char * path); + void useDefaultAppearance(); + void useAlternateAppearance(); + bool isUsingAlternateAppearance() const; + +protected: + + // scheduleForAlter() strategies available for use by derived classes. + void scheduleForAlter_scheduleTopmostWorldParent(); + + void nullWatchers(); + + virtual void positionChanged(bool dueToParentChange, const Vector &oldPosition); + virtual void rotationChanged(bool dueToParentChange); + virtual void positionAndRotationChanged(bool dueToParentChange, const Vector &oldPosition); + +private: + + enum + { + ROTATIONS_BETWEEN_REORTHONORMALIZE = 255 + }; + +private: + + Object(const Object &); + Object &operator =(const Object &); + +private: + + void reorthonormalize(); + void cellChanged(bool dueToParentChange); + + void setObjectToWorldDirty(bool objectToWorldDirty) const; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // Begin AlterScheduler Interface + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + // ScheduleData creation. + bool hasScheduleData() const; + void createScheduleDataIfNecessary(ScheduleTime initialMostRecentAlterTime); + + // Most recent alter time management. + ScheduleTime getMostRecentAlterTime() const; + void setMostRecentAlterTime(ScheduleTime mostRecentAlterTime); + + // Container management. + bool isInAlterNextFrameList() const; + void insertIntoAlterNextFrameList(Object *afterThisObject); + void removeFromAlterNextFrameList(); + + int getAlterSchedulePhase() const; + void setAlterSchedulePhase(int schedulePhaseIndex); + + bool isInAlterNowList() const; + void insertIntoAlterNowList(Object *afterThisObject); + void removeFromAlterNowList(); + + bool isInConcludeList() const; + void insertIntoConcludeList(Object *afterThisObject); + void removeFromConcludeList(); + + void *getScheduleTimeMapIterator(); + + // Container traversal. + Object *getNextFromAlterNowList(); + Object *getPreviousFromAlterNowList(); + + Object *getNextFromAlterNextFrameList(); + Object *getPreviousFromAlterNextFrameList(); + + Object *getNextFromConcludeList(); + Object *getPreviousFromConcludeList(); + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + void setIsAltering(bool isAltering); +#endif + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // End AlterScheduler Interface + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + typedef stdvector::fwd PropertyList; + +protected: + PropertyList * const m_propertyList; + +private: + + bool m_inWorld:1; + bool m_active:1; + bool m_kill:1; + bool m_authoritative:1; + bool m_childObject:1; + bool mutable m_objectToWorldDirty:1; +#if OBJECT_SUPPORTS_DESTROYED_FLAG + bool m_isDestroyed:1; +#endif + +#if OBJECT_SUPPORTS_IS_ALTERING_FLAG + bool m_isAltering:1; +#endif + + const ObjectTemplate *m_objectTemplate; + const NotificationList *m_notificationList; + char *m_debugName; + + NetworkId m_networkId; + + Appearance *m_appearance; + Controller *m_controller; + Dynamics *m_dynamics; + + Object *m_attachedToObject; + typedef stdvector::fwd AttachedObjects; + AttachedObjects *m_attachedObjects; + DpvsObjects *m_dpvsObjects; + + int m_rotations; + Vector m_scale; + Transform m_objectToParent; + Transform *m_objectToWorld; + + mutable WatchedByList m_watchedByList; + + Container *m_containerProperty; + CollisionProperty *m_collisionProperty; + + SpatialSubdivisionHandle *m_spatialSubdivisionHandle; + + bool m_useAlterScheduler; + ScheduleData *m_scheduleData; + + bool m_shouldBakeIntoMesh; + + Appearance *m_defaultAppearance; + Appearance *m_alternateAppearance; + +protected: + + ContainedByProperty *m_containedBy; +}; + +// ====================================================================== +/** + * Returns the object's template. + */ +inline const ObjectTemplate *Object::getObjectTemplate() const +{ + return m_objectTemplate; +} + +// ---------------------------------------------------------------------- +// Get the object's name +// +// Return value: +// +// Const pointer to the object's name +// +// Remarks: +// +// This return may return NULL. + +inline const char *Object::getDebugName() const +{ + return m_debugName; +} + +// ---------------------------------------------------------------------- +/** + * Get the scale for this object. + * + * @return Const reference to the scale vector for this object's appearance + */ + +inline const Vector &Object::getScale() const +{ + return m_scale; +} + +// ---------------------------------------------------------------------- +/** + * Get the controller for an object. + * + * The return value may be NULL. + * + * @return Const pointer to the controller + */ + +inline const Controller *Object::getController() const +{ + return m_controller; +} + +// ---------------------------------------------------------------------- +/** + * Get the controller for an object. + * + * The return value may be NULL. + * + * @return Non-const pointer to the controller + */ + +inline Controller *Object::getController() +{ + return m_controller; +} + +// ---------------------------------------------------------------------- +/** + * Get the dynamics for an object. + * + * The return value may be NULL. + * + * @return Const pointer to the dynamics + */ + +inline const Dynamics *Object::getDynamics() const +{ + return m_dynamics; +} + +// ---------------------------------------------------------------------- +/** + * Get the dynamics for an object. + * + * The return value may be NULL. + * + * @return Non-const pointer to the dynamics + */ + +inline Dynamics *Object::getDynamics() +{ + return m_dynamics; +} + +// ---------------------------------------------------------------------- +/** + * Get the const appearance for this object. + * + * @return Const Pointer to the appearance for this object + */ + +inline const Appearance *Object::getAppearance() const +{ + return m_appearance; +} + +// ---------------------------------------------------------------------- +/** + * Get the appearance for this object. + * + * @return Pointer to the appearance for this object + */ + +inline Appearance *Object::getAppearance() +{ + return m_appearance; +} + +// ---------------------------------------------------------------------- +/** + * Get the parent object for this object. + * + * This routine will return NULL if the object is not a child object. + */ + +inline Object *Object::getParent() +{ + return m_childObject ? m_attachedToObject : NULL; +} + +// ---------------------------------------------------------------------- +/** + * Get the parent object for this object. + * + * This routine will return NULL if the object is not a child object. + */ + +inline const Object *Object::getParent() const +{ + return m_childObject ? m_attachedToObject : NULL; +} + +// ---------------------------------------------------------------------- +/** + * Get the object this object is attached to. + * + * The object may be a child of the attached object. + */ + +inline Object *Object::getAttachedTo() +{ + return m_attachedToObject; +} + +// ---------------------------------------------------------------------- +/** + * Get the parent object for this object. + * + * The object may be a child of the attached object. + */ + +inline const Object *Object::getAttachedTo() const +{ + return m_attachedToObject; +} + +// ---------------------------------------------------------------------- +/** + * Get the object-to-parent transformation for this object. + * + * @return Const reference to the object-to-parent transform for this object + */ + +inline const Transform &Object::getTransform_o2p() const +{ + return m_objectToParent; +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-to-world transformation for this object. + * + * @return Const reference to the parent-to-world transform for this object + */ + +inline const Transform &Object::getTransform_p2w() const +{ + if (m_attachedToObject) + return m_attachedToObject->getTransform_o2w(); + + return Transform::identity; +} + +// ---------------------------------------------------------------------- +/** + * Get the position of this object in its parent space. + * + * This routine returns a temporary. + */ + +inline const Vector Object::getPosition_p() const +{ + return m_objectToParent.getPosition_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the position of this object in world space. + * + * This routine returns a temporary. + */ + +inline const Vector Object::getPosition_w() const +{ + return getTransform_o2w().getPosition_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the position of the object in cell space. + * + * This routine returns a temporary. + */ + +inline const Vector Object::getPosition_c() const +{ + return getTransform_o2c().getPosition_p(); +} + +// ---------------------------------------------------------------------- +/** + * Set the position of this object in its parent space. + * + * @param newPositionInParentSpace New position in the parent's space + */ + +inline void Object::setPosition_p(const Vector &newPositionInParentSpace) +{ + const Vector oldPosition = getPosition_p(); + m_objectToParent.setPosition_p(newPositionInParentSpace); + positionChanged(false, oldPosition); +} + +// ---------------------------------------------------------------------- +/** + * Set the position of this object in world space. + * + * @param newPositionInWorldSpace New position in the world space + */ + +inline void Object::setPosition_w(const Vector &newPositionInWorldSpace) +{ + if (m_attachedToObject) + setPosition_p(m_attachedToObject->rotateTranslate_w2o(newPositionInWorldSpace)); + else + setPosition_p(newPositionInWorldSpace); +} + +// ---------------------------------------------------------------------- +/** + * Set the object-to-parent transform for this object. + * + * @param newObjectToParentTransform New object-to-parent transform + */ + +inline void Object::setTransform_o2p(const Transform &newObjectToParentTransform) +{ + const Vector oldPosition = getPosition_p(); + m_objectToParent = newObjectToParentTransform; + positionAndRotationChanged(false, oldPosition); +} + +// ---------------------------------------------------------------------- +/** + * Set the object-to-parent transform for this object. + * + * @param i Unit vector along the X axis + * @param j Unit vector along the Y axis + * @param k Unit vector along the Z axis + */ + +inline void Object::setTransformIJK_o2p(const Vector &i, const Vector &j, const Vector &k) +{ + m_objectToParent.setLocalFrameIJK_p(i, j, k); + rotationChanged(false); +} + +// ---------------------------------------------------------------------- +/** + * Set the object-to-parent transform for this object. + * + * @param k Unit vector along the Z axis + * @param j Unit vector along the Y axis + */ + +inline void Object::setTransformKJ_o2p(const Vector &k, const Vector &j) +{ + m_objectToParent.setLocalFrameKJ_p(k, j); + rotationChanged(false); +} + +// ---------------------------------------------------------------------- +/** + * Reorthonormalize the object-to-world transform. + * + * Repeated rotations will introduce numerical error into the transform, + * which will cause the upper 3x3 matrix to become non-orthonormal. If + * enough error is introduced, weird errors will begin to occur when using + * the transform. + * + * This routine attempts to reduce the numerical error by reorthonormalizing + * the upper 3x3 matrix. + */ + +inline void Object::reorthonormalize() +{ + m_objectToParent.reorthonormalize(); + m_rotations = 0; +} + +// ---------------------------------------------------------------------- +/** + * Yaw the object around its Y axis. + * + * This routine will rotate the object around its Y axis by the specified + * number of radians. + * + * Positive rotations are clockwise when viewed from the positive side of + * the axis being rotated about looking towards the origin. + * + * @param radians Radians to yaw the object. + * @see Object::pitch_o(), Object::roll_o(), + */ + +inline void Object::yaw_o(real radians) +{ + if (radians != 0.0f) + { + m_objectToParent.yaw_l(radians); + if (++m_rotations >= ROTATIONS_BETWEEN_REORTHONORMALIZE) + reorthonormalize(); + rotationChanged(false); + } +} + +// ---------------------------------------------------------------------- +/** + * Pitch the object around its X axis. + * + * This routine will rotate the object around its X axis by the specified + * number of radians. + * + * Positive rotations are clockwise when viewed from the positive side of + * the axis being rotated about looking towards the origin. + * + * @param radians Radians to pitch the object. + * @see Object::yaw_o(), Object::roll_o(), + */ + +inline void Object::pitch_o(real radians) +{ + if (radians != 0.0f) + { + m_objectToParent.pitch_l(radians); + if (++m_rotations >= ROTATIONS_BETWEEN_REORTHONORMALIZE) + reorthonormalize(); + rotationChanged(false); + } +} + +// ---------------------------------------------------------------------- +/** + * Roll the object around its Z axis. + * + * This routine will rotate the object around its Z axis by the specified + * number of radians. + * + * Positive rotations are clockwise when viewed from the positive side of + * the axis being rotated about looking towards the origin. + * + * @param radians Radians to roll the object. + * @see Object::yaw_o(), Object::pitch_o(), + */ + +inline void Object::roll_o(real radians) +{ + if (radians != 0.0f) + { + m_objectToParent.roll_l(radians); + if (++m_rotations >= ROTATIONS_BETWEEN_REORTHONORMALIZE) + reorthonormalize(); + rotationChanged(false); + } +} + +// ---------------------------------------------------------------------- +/** + * Reset the objectToParent transform's rotations. + * + * This does NOT affect the object's position. This will make the object + * have the same orientation as its parent. + */ + +inline void Object::resetRotate_o2p() +{ + m_objectToParent.resetRotate_l2p(); + m_rotations = 0; + rotationChanged(false); +} + +// ---------------------------------------------------------------------- +/** + * Reset the objectToParent transform. + * + * This will make the object have the same orientation and position as its parent. + */ + +inline void Object::resetRotateTranslate_o2p() +{ + const Vector oldPosition = getPosition_p(); + m_objectToParent.resetRotateTranslate_l2p(); + m_rotations = 0; + positionAndRotationChanged(false, oldPosition); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the X axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the X axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameI_p() const +{ + return m_objectToParent.getLocalFrameI_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the Y axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the Y axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameJ_p() const +{ + return m_objectToParent.getLocalFrameJ_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the Z axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the Z axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameK_p() const +{ + return m_objectToParent.getLocalFrameK_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the X axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the X axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameI_w() const +{ + return getTransform_o2w().getLocalFrameI_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the Y axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the Y axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameJ_w() const +{ + return getTransform_o2w().getLocalFrameJ_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the parent-space vector pointing along the Z axis of this frame of reference. + * + * This routine returns a temporary. + * + * @return The vector pointing along the Z axis of the frame in parent space + */ + +inline const Vector Object::getObjectFrameK_w() const +{ + return getTransform_o2w().getLocalFrameK_p(); +} + +// ---------------------------------------------------------------------- +/** + * Get the object-space vector pointing along the X axis of the parent of reference. + * + * This routine returns a temporary. + * + * The vector returned is in local space. + * + * @return The vector pointing along the X axis of the parent's frame in local space + */ + +inline const Vector Object::getParentFrameI_o() const +{ + return m_objectToParent.getParentFrameI_l(); +} + +// ---------------------------------------------------------------------- +/** + * Get the object-space vector pointing along the Y axis of the parent of reference. + * + * This routine returns a temporary. + * + * The vector returned is in local space. + * + * @return The vector pointing along the Y axis of the parent's frame in local space + */ + +inline const Vector Object::getParentFrameJ_o() const +{ + return m_objectToParent.getParentFrameJ_l(); +} + +// ---------------------------------------------------------------------- +/** + * Get the object-space vector pointing along the Z axis of the parent of reference. + * + * This routine returns a temporary. + * + * The vector returned is in local space. + * + * @return The vector pointing along the Z axis of the parent's frame in local space + */ + +inline const Vector Object::getParentFrameK_o() const +{ + return m_objectToParent.getParentFrameK_l(); +} + +// ---------------------------------------------------------------------- +/** + * Rotate vector from the object's frame to the parent frame. + * + * @param vector Vector to rotate from object space into parent space + * @return The source object-space vector rotated into parent space + */ + +inline const Vector Object::rotate_o2p(const Vector &vector) const +{ + return m_objectToParent.rotate_l2p(vector); +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the object's frame to the parent frame. + * + * @param vector Vector to rotate and translate from object space into parent space + * @return The source object-space vector rotated and translated into parent space + */ + +inline const Vector Object::rotateTranslate_o2p(const Vector &vector) const +{ + return m_objectToParent.rotateTranslate_l2p(vector); +} + +// ---------------------------------------------------------------------- +/** + * Rotate vector from the parent frame to the object's frame. + * + * @param vector Vector to rotate from parent space into object space + * @return The source parent-space vector rotated into object space + */ + +inline const Vector Object::rotate_p2o(const Vector &vector) const +{ + return m_objectToParent.rotate_p2l(vector); +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the parent frame to the object's frame. + * + * @param vector Vector to rotate and translate from parent space into object space + * @return The source parent-space vector rotated into object space + */ + +inline const Vector Object::rotateTranslate_p2o(const Vector &vector) const +{ + return m_objectToParent.rotateTranslate_p2l(vector); +} + +// ---------------------------------------------------------------------- +/** + * Rotate vector from the object's frame to the world frame. + * + * @param vector Vector to rotate from object space into world space + * @return The source object-space vector rotated into world space + */ + +inline const Vector Object::rotate_o2w(const Vector &vector) const +{ + return getTransform_o2w().rotate_l2p(vector); +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the object's frame to the world frame. + * + * @param vector Vector to rotate and translate from object space into world space + * @return The source object-space vector rotated and translated into world space + */ + +inline const Vector Object::rotateTranslate_o2w(const Vector &vector) const +{ + return getTransform_o2w().rotateTranslate_l2p(vector); +} + +// ---------------------------------------------------------------------- +/** + * Rotate vector from the world frame to the object's frame. + * + * @param vector Vector to rotate from world space into object space + * @return The source world-space vector rotated into object space + */ + +inline const Vector Object::rotate_w2o(const Vector &vector) const +{ + return getTransform_o2w().rotate_p2l(vector); +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the world frame to the object's frame. + * + * @param vector Vector to rotate and translate from world space into object space + * @return The source world-space vector rotated into object space + */ + +inline const Vector Object::rotateTranslate_w2o(const Vector &vector) const +{ + return getTransform_o2w().rotateTranslate_p2l(vector); +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the parent frame to the world frame. + * + * @param vector Vector to rotate and translate from parent space into world space + * @return The source parent-space vector rotated into world space + */ + +inline const Vector Object::rotateTranslate_p2w(const Vector &vector) const +{ + if (m_attachedToObject) + return m_attachedToObject->rotateTranslate_o2w(vector); + + return vector; +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the parent frame to the world frame. + * + * @param vector Vector to rotate from parent space into world space + * @return The source parent-space vector rotated into world space + */ + +inline const Vector Object::rotate_p2w(const Vector &vector) const +{ + if (m_attachedToObject) + return m_attachedToObject->rotate_o2w(vector); + + return vector; +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the world frame to the parent frame. + * + * @param vector Vector to rotate from world space into parent space + * @return The source world-space vector rotated into parent space + */ + +inline const Vector Object::rotate_w2p(const Vector &vector) const +{ + if (m_attachedToObject) + return m_attachedToObject->rotate_w2o(vector); + + return vector; +} + +// ---------------------------------------------------------------------- +/** + * Calculate vector from the world frame to the parent frame. + * + * @param vector Vector to rotate from world space into parent space + * @return The source world-space vector rotated into parent space + */ + +inline const Vector Object::rotateTranslate_w2p(const Vector &vector) const +{ + if (m_attachedToObject) + return m_attachedToObject->rotateTranslate_w2o(vector); + + return vector; +} + +// ---------------------------------------------------------------------- +/** + * Move the object in it's own local space. + * + * This routine moves the object according to its current frame of reference. + * Therefore, moving along the Z axis will move the object forward in the direction + * in which it is pointed. + * + * @param vectorInObjectSpace Offset to move in local space + * @see Object::move_p() + */ + +inline void Object::move_o(const Vector &vectorInObjectSpace) +{ + move_p(rotate_o2p(vectorInObjectSpace)); +} + +// ---------------------------------------------------------------------- +/** + * @internal + */ + +inline WatchedByList &Object::getWatchedByList() const +{ + return m_watchedByList; +} + +// ---------------------------------------------------------------------- + +inline const Object::DpvsObjects *Object::getDpvsObjects() const +{ + return m_dpvsObjects; +} + +// ---------------------------------------------------------------------- + +inline Container * Object::getContainerProperty() +{ + return m_containerProperty; +} + +// ---------------------------------------------------------------------- + +inline Container const * Object::getContainerProperty() const +{ + return m_containerProperty; +} + +//----------------------------------------------------------------------- + +inline ContainedByProperty * Object::getContainedByProperty() +{ + return m_containedBy; +} + +//----------------------------------------------------------------------- + +inline ContainedByProperty const * Object::getContainedByProperty() const +{ + return m_containedBy; +} + +// ---------------------------------------------------------------------- + +inline CollisionProperty * Object::getCollisionProperty() +{ + return m_collisionProperty; +} + +// ---------------------------------------------------------------------- + +inline CollisionProperty const * Object::getCollisionProperty() const +{ + return m_collisionProperty; +} + +// ---------------------------------------------------------------------- +/** + * Determine if this object is a child object. + * + * If the object is a child object, it will have a parent object. + * + * @return True if the object is a child object, otherwise false. + */ + +inline bool Object::isChildObject() const +{ + return m_childObject; +} + +// ---------------------------------------------------------------------- + +inline bool Object::getKill() const +{ + return m_kill; +} + +// ---------------------------------------------------------------------- +/** + * Return the object is authoritative. + */ + +inline bool Object::isAuthoritative() const +{ + return m_authoritative; +} + +// ---------------------------------------------------------------------- +/** + * Specify whether the object is authoritative. + */ + +inline void Object::setAuthoritative(bool newAuthoritative) +{ + m_authoritative = newAuthoritative; +} + +// ---------------------------------------------------------------------- +/** + * Check if the object is active. + * + * @return True if the object is active, otherwise false + */ + +inline bool Object::isActive() const +{ + return m_active; +} + +// ---------------------------------------------------------------------- +/** + * Returns whether the object is in the world or not. + */ + +inline bool Object::isInWorld() const +{ + return m_inWorld; +} + +// ---------------------------------------------------------------------- + +inline const NetworkId &Object::getNetworkId() const +{ + return m_networkId; +} + +inline bool Object::getShouldBakeIntoMesh() const +{ + return m_shouldBakeIntoMesh; +} + +inline void Object::setShouldBakeIntoMesh(bool bake) +{ + m_shouldBakeIntoMesh = bake; +} + +inline bool Object::isUsingAlternateAppearance() const +{ + return m_appearance == m_alternateAppearance; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectList.cpp b/engine/shared/library/sharedObject/src/shared/object/ObjectList.cpp new file mode 100644 index 00000000..9e72d27d --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectList.cpp @@ -0,0 +1,425 @@ +// ====================================================================== +// +// ObjectList.cpp +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectList.h" + +#include "sharedObject/AlterResult.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/Object.h" + +#include + +// ====================================================================== + +namespace ObjectListNamespace +{ + void setRegionOfInfluenceEnabled(const Object *const object, const bool enabled) + { + object->setRegionOfInfluenceEnabled(enabled); + + for (int i = 0; i < object->getNumberOfChildObjects(); ++i) + setRegionOfInfluenceEnabled(object->getChildObject(i), enabled); + } +} + +// ====================================================================== +// Construct an ObjectList + +ObjectList::ObjectList( + int initialVectorSize // The initial entries set aside for the object list + ) +: + m_altering(false), + m_objectVector(new ObjectVector()), + m_alterSafeObjectVector(new ObjectVector()) +{ + DEBUG_FATAL(initialVectorSize < 0, ("negative vector size")); + + // Reserve the requested amount of entries to reduce further allocation + + m_objectVector->reserve(static_cast (initialVectorSize)); + m_alterSafeObjectVector->reserve(static_cast (initialVectorSize)); +} + +// ---------------------------------------------------------------------- +/** + * Destroy an ObjectList. + */ + +ObjectList::~ObjectList() +{ + delete m_objectVector; + delete m_alterSafeObjectVector; +} + +// ---------------------------------------------------------------------- +/** + * Add an Object to the ObjectList. + * + * This routine will call Fatal in debug compiles if it is passed a NULL + * object. + * + * This routine will call Fatal in debug compiles if the object list + * overflows. + * + * @param objectToAdd Object to add to the ObjectList + */ + +void ObjectList::addObject(Object *objectToAdd) +{ + NOT_NULL(objectToAdd); + + // Add the new object + + m_objectVector->push_back(objectToAdd); +} + +// ---------------------------------------------------------------------- +/** + * Remove an Object from the ObjectList. + * + * This routine will call Fatal in debug compiles if it is passed a NULL + * object. + * + * @param objectToRemove Pointer to the object to remove + */ + +void ObjectList::removeObject(const Object *objectToRemove) +{ + int index = 0; + if (find(objectToRemove, &index)) + removeObjectByIndex(objectToRemove, index); +} + +// ---------------------------------------------------------------------- + +void ObjectList::removeObjectByIndex(const Object* object, int index) +{ + NOT_NULL(object); + DEBUG_FATAL(index >= static_cast(m_objectVector->size()), ("Index out of range")); + DEBUG_FATAL((*m_objectVector)[static_cast(index)] != object, ("Object is not the one indexed.")); + + // Replace the found entry with the entry from the back of the vector + // so there is no shifting of the items in the vector. + (*m_objectVector)[static_cast(index)] = m_objectVector->back(); + + // Remove the last item in the vector. + m_objectVector->pop_back(); + + // NULL the object from the alter-safe object list. + uint size = m_alterSafeObjectVector->size(); + for (uint i = 0; i < size; ++i) + { + if ((*m_alterSafeObjectVector)[i] == object) + { + (*m_alterSafeObjectVector)[i] = NULL; + return; + } + } +} + + +// ---------------------------------------------------------------------- +/** + * Remove all Objects from the ObjectList. + * + * Removes all Objects from the ObjectList + * + * This routine may not be called between prepareToAlter() and alter(). + * + * If deleteObjects is true, this routine will call delete for all objects in the list + * + * @param deleteObjects Flag to delete all objects when they are removed + */ + +void ObjectList::removeAll (bool deleteObjects) +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + if (deleteObjects) + { + ObjectVector::iterator end = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + delete (*i); + } + + m_objectVector->clear(); +} + +// ---------------------------------------------------------------------- + +void ObjectList::addToWorld() +{ + ObjectVector::iterator iEnd = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != iEnd; ++i) + (*i)->addToWorld(); +} + +// ---------------------------------------------------------------------- + +void ObjectList::removeFromWorld() +{ + ObjectVector::iterator iEnd = m_objectVector->end(); + for (ObjectVector::iterator i = m_objectVector->begin(); i != iEnd; ++i) + (*i)->removeFromWorld(); +} + +// ---------------------------------------------------------------------- +/** + * Prepare to call alter() on this object list. + * + * This routine must be called before calling alter(). It will copy setup + * the ObjectList so that objects may be added and removed from the ObjectList + * during the alter() without affecting that frame's list of objects that are + * are being altered. + */ + +void ObjectList::prepareToAlter() +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + m_altering = true; + + // Duplicate the object vector + + (*m_alterSafeObjectVector) = (*m_objectVector); +} + +// ---------------------------------------------------------------------- +/** + * Call alter() for all objects in the ObjectList. + * + * prepareToAlter() must be called before this routine can be called. + * + * This routine will simply iterate over all the objects in the ObjectList + * and call their alter routines with the specified time. + * + * @param time Time to pass to each Object's alter routine + * @see ObjectList::prepareToAlter() + */ + +float ObjectList::alter(real time) +{ + DEBUG_FATAL(!m_altering, ("prepareToAlter was not called")); + + float finalAlterResult = AlterResult::cms_keepNoAlter; + + for (uint32 i = 0; i < m_alterSafeObjectVector->size(); ++i) + { + // Cache the object pointer because the iter value may be nulled if the object is removed from the list withing its alter() + Object *obj = (*m_alterSafeObjectVector)[i]; + if (!obj) + continue; + + if (obj->isInitialized()) + { + float const alterResult = obj->alter(time); + if (alterResult == AlterResult::cms_kill) //lint !e777 // Testing floats for equality // It's okay, we're using constants. + { + // Make sure the object is still in the object list before removing it + if ((*m_alterSafeObjectVector)[i] != NULL) + removeObject(obj); + delete obj; + } + else + AlterResult::incorporateAlterResult(finalAlterResult, alterResult); + } + } + + m_alterSafeObjectVector->clear(); + m_altering = false; + + return finalAlterResult; +} + +// ---------------------------------------------------------------------- +/** + * Call conclude() for all objects in the ObjectList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectList + * and call their conclude routines with the specified time. + */ + +void ObjectList::conclude() +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + (*i)->conclude(); + } +} + +// ---------------------------------------------------------------------- +/** + * Call addToScene() for all objects in the ObjectList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectList + * and call their addToScene() routine with the specified camera. + * + * @param camera Camera rendering the scene. + * @param excludedObject Object to exclude from the scene. + */ + +void ObjectList::setRegionOfInfluenceEnabled(bool enabled) const +{ + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + ObjectListNamespace::setRegionOfInfluenceEnabled(*i, enabled); +} + +// ---------------------------------------------------------------------- +/** + * Call addToScene() for all objects in the ObjectList. + * + * This routine may not be called between prepareToAlter() and alter(). + * + * This routine will simply iterate over all the objects in the ObjectList + * and call their addToScene() routine with the specified camera. + * + * @param camera Camera rendering the scene. + * @param excludedObject Object to exclude from the scene. + */ + +void ObjectList::render(const Object *excludedObject) const +{ + DEBUG_FATAL(m_altering, ("m_altering")); + + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + Object *const object = *i; + if (object && (object != excludedObject)) + { + const Appearance *const appearance = object->getAppearance(); + if (appearance) + { + appearance->setTransform_w(object->getTransform_o2w()); + appearance->objectListCameraRender(); + } + } + } +} + +// ---------------------------------------------------------------------- +/** + * Find the index of an object in an object list. + * + * Accepts an optional index to be used to return the object's index + * in the object list. + * + * This routine will simply iterate over all the objects in the ObjectList + * searching for the objectToCheck, and returns true with the index if + * found, and false otherwise. + * + * @param objectToCheck Object to find + * @param index Object's index in the object list + */ + +bool ObjectList::find(const Object *objectToCheck, int *index) const +{ + ObjectVector::iterator end = m_objectVector->end(); + + for (ObjectVector::iterator i = m_objectVector->begin(); i != end; ++i) + { + Object *obj = (*i); + + if (obj == objectToCheck) + { + if (index) + *index = std::distance(m_objectVector->begin(), i); + return true; + } + + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool ObjectList::isEmpty() const +{ + return m_objectVector->empty(); +} + +// ---------------------------------------------------------------------- +/** + * Return the number of objects contained in the object list. + * + * @return The number of objects contained in the object list + */ + +int ObjectList::getNumberOfObjects() const +{ + return static_cast (m_objectVector->size()); +} + +// ---------------------------------------------------------------------- +/** + * Get an object in the object list. + * + * @param index Index of the object in the object list + */ + +Object *ObjectList::operator [](int index) +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get a const object from the object list. + * + * @param index Index of the object in the object list + */ + +const Object *ObjectList::operator [](int index) const +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get an object in the object list. + * + * @param index Index of the object in the object list + */ + +Object *ObjectList::getObject(int index) +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ---------------------------------------------------------------------- +/** + * Get a const object from the object list. + * + * @param index Index of the object in the object list + */ + +const Object *ObjectList::getObject(int index) const +{ + DEBUG_FATAL(index < 0 || index >= getNumberOfObjects(), ("index out of range %d/%d", index, getNumberOfObjects())); + return (*m_objectVector)[static_cast (index)]; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectList.h b/engine/shared/library/sharedObject/src/shared/object/ObjectList.h new file mode 100644 index 00000000..25f175fa --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectList.h @@ -0,0 +1,73 @@ +// ====================================================================== +// +// ObjectList.h +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2001, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ObjectList_H +#define INCLUDED_ObjectList_H + +// ====================================================================== + +class Object; +class Camera; + +// ====================================================================== +// Contain a list of pointers to objects. +// +// Objects may exist in more than one ObjectList simultaneously. + +class ObjectList +{ +public: + + explicit ObjectList(int initialVectorSize=0); + ~ObjectList(); + + void addObject(Object *object); + void removeObject(const Object *object); + + void removeAll(bool deleteObjects=false); + + bool isEmpty() const; + int getNumberOfObjects() const; + + Object *getObject(int index); + const Object *getObject(int index) const; + + Object *operator [](int index); + const Object *operator [](int index) const; + + bool find(const Object* objectToCheck, int* index=0) const; + void removeObjectByIndex(const Object*, int index); + + void addToWorld(); + void removeFromWorld(); + + void prepareToAlter(); + float alter(real time); + void conclude(); + + void setRegionOfInfluenceEnabled(bool enabled) const; + void render(const Object *omitObject) const; + +private: + + typedef stdvector::fwd ObjectVector; + bool m_altering; + ObjectVector * m_objectVector; + ObjectVector * m_alterSafeObjectVector; + +private: + + // disable these routines + ObjectList(const ObjectList &); + ObjectList &operator =(const ObjectList &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.cpp b/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.cpp new file mode 100644 index 00000000..8be51dd9 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.cpp @@ -0,0 +1,117 @@ +// ====================================================================== +// +// ObjectNotifcation.cpp +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectNotification.h" + +// ====================================================================== +/** + * Create a notification object. + */ + +ObjectNotification::ObjectNotification() +{ +} + +// ---------------------------------------------------------------------- +/** + * Destroy a notification object. + */ + +ObjectNotification::~ObjectNotification() +{ +} + +// ---------------------------------------------------------------------- +/** + * Get the priority for this notification. + * + * This will affect the order in which the notification gets called. + */ + +int ObjectNotification::getPriority() const +{ + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object should be added to the world. + */ + +void ObjectNotification::addToWorld(Object &) const +{ +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object should be removed from the world. + */ + +void ObjectNotification::removeFromWorld(Object &) const +{ +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object's position likely has changed. + */ + +bool ObjectNotification::positionChanged(Object &, bool, const Vector &) const +{ + return true; +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object's orientation likely has changed. + */ + +void ObjectNotification::rotationChanged(Object &, bool) const +{ +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object's position and/or orientation likely has changed. + */ + +bool ObjectNotification::positionAndRotationChanged(Object &, bool, const Vector &) const +{ + return true; +} + +// ---------------------------------------------------------------------- +/** + * Notify that this object is changing cells. + */ + +void ObjectNotification::cellChanged(Object &, bool) const +{ +} + +// ---------------------------------------------------------------------- +/** + * Notify that this that its extent has changed + */ + +void ObjectNotification::extentChanged(Object &) const +{ +} + +// ---------------------------------------------------------------------- +/** + * Notify that this that the parent's pob fixup is complete + */ + +void ObjectNotification::pobFixupComplete(Object &) const +{ +} + + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.h b/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.h new file mode 100644 index 00000000..c2b3c5c2 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectNotification.h @@ -0,0 +1,62 @@ +// ====================================================================== +// +// ObjectNotifcation.h +// Copyright 2002 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ObjectNotifcation_H +#define INCLUDED_ObjectNotifcation_H + +// ====================================================================== + +class Object; +class Vector; + +// ====================================================================== + +class ObjectNotification +{ +public: + + virtual int getPriority() const; + + virtual void addToWorld(Object &object) const; + virtual void removeFromWorld(Object &object) const; + + virtual bool positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + virtual void rotationChanged(Object &object, bool dueToParentChange) const; + virtual bool positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + virtual void cellChanged(Object &object, bool dueToParentChange) const; + virtual void extentChanged(Object &object) const; + virtual void pobFixupComplete(Object &object) const; + +private: + + int positionChanged(Object &object) const; + int positionAndRotationChanged(Object &object) const; + + int addToWorld(const Object &object) const; + int removeFromWorld(const Object &object) const; + + int positionChanged(const Object &object, const Vector &oldPosition) const; + int rotationChanged(const Object &object) const; + int positionAndRotationChanged(const Object &object, const Vector &oldPosition) const; + + int cellChanged(const Object &object) const; + +protected: + + ObjectNotification(); + virtual ~ObjectNotification(); + +private: + + ObjectNotification(const ObjectNotification &); + ObjectNotification &operator =(const ObjectNotification &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.cpp b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.cpp new file mode 100644 index 00000000..5729afef --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.cpp @@ -0,0 +1,263 @@ +// ====================================================================== +// +// ObjectTemplate.cpp +// copyright 1999 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectTemplate.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/CrashReportInformation.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedObject/Object.h" +#include "sharedObject/ObjectTemplateList.h" + +#include + +// ====================================================================== + +namespace ObjectTemplateNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void remove(); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + char s_crashReportInfoConstructor[MAX_PATH * 2]; + char s_crashReportInfoLoadFromIff[MAX_PATH * 2]; +} + +using namespace ObjectTemplateNamespace; + +// ====================================================================== + +void ObjectTemplateNamespace::remove() +{ + CrashReportInformation::removeDynamicText(s_crashReportInfoConstructor); + CrashReportInformation::removeDynamicText(s_crashReportInfoLoadFromIff); +} + +// ====================================================================== + +void ObjectTemplate::install() +{ + s_crashReportInfoConstructor[0] = '\0'; + CrashReportInformation::addDynamicText(s_crashReportInfoConstructor); + + s_crashReportInfoLoadFromIff[0] = '\0'; + CrashReportInformation::addDynamicText(s_crashReportInfoLoadFromIff); + + ExitChain::add(remove, "ObjectTemplate"); +} + +// ====================================================================== +/** + * Construct an ObjectTemplate. + * + * @param newName name of the ObjectTemplate + * + */ +ObjectTemplate::ObjectTemplate(const std::string & filename) : + DataResource(filename.c_str ()), + m_baseData(0) +{ + //-- Track name of most recently loading object template name to give us more + // data to work with when we receive crash info. + IGNORE_RETURN(snprintf(s_crashReportInfoConstructor, sizeof(s_crashReportInfoConstructor) - 1, "ObjectTemplate_Constructor: %s\n", !filename.empty() ? filename.c_str() : "")); + s_crashReportInfoConstructor[sizeof(s_crashReportInfoConstructor) - 1] = '\0'; +} + +// ---------------------------------------------------------------------- +/** + * Destroy an ObjectTemplate. + */ + +ObjectTemplate::~ObjectTemplate() +{ + if (m_baseData != 0) + { + m_baseData->releaseReference(); + m_baseData = 0; + } +} + +// ---------------------------------------------------------------------- + +ServerObjectTemplate * ObjectTemplate::asServerObjectTemplate() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +ServerObjectTemplate const * ObjectTemplate::asServerObjectTemplate() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +SharedObjectTemplate * ObjectTemplate::asSharedObjectTemplate() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +SharedObjectTemplate const * ObjectTemplate::asSharedObjectTemplate() const +{ + return 0; +} + +// ---------------------------------------------------------------------- + +void ObjectTemplate::load(Iff & /*iff*/) +{ + DEBUG_FATAL (true, ("ObjectTemplate::load [%s] - this function should not be called", getName())); +} + +// ---------------------------------------------------------------------- +/** + * Creates an object from an iff file. + * + * @param iffFilename file name of iff file to read + * + * @return the new object + */ +Object *ObjectTemplate::createObject(const char *const fileName) +{ + const ObjectTemplate *const objectTemplate = ObjectTemplateList::fetch(fileName); + if (objectTemplate) + { + Object *const object = objectTemplate->createObject(); + objectTemplate->releaseReference (); + + return object; + } + + return 0; +} + +// ---------------------------------------------------------------------- +/** + * Create a unique Object for this ObjectTemplate. + * + * This routine should be overloaded in derived classes as appropriate. + * + * Derived classes should not chain down to this routine. + * + * @return An Object for the specified ObjectTemplate + */ + +Object *ObjectTemplate::createObject() const +{ + return new Object(this, NetworkId::cms_invalid); +} + +// ---------------------------------------------------------------------- + +/** + * Adds a reference on this template and also adds a reference on the + * template's base. + */ +void ObjectTemplate::addReference() const +{ + if (m_baseData != NULL) + m_baseData->addReference(); + + DataResource::addReference(); +} + +// ---------------------------------------------------------------------- +/** + * Releases a reference on this template and also releases a reference on the + * template's base. + */ +void ObjectTemplate::releaseReference() const +{ + if (m_baseData != NULL) + m_baseData->releaseReference(); + + DataResource::releaseReference(); +} + + +// ====================================================================== + +void ObjectTemplate::release() const +{ + ObjectTemplateList::release(*this); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplate::loadFromIff(Iff &iff) +{ + //-- Track name of most recently loading object template name to give us more + // data to work with when we receive crash info. + char const *const filename = iff.getFileName(); + IGNORE_RETURN(snprintf(s_crashReportInfoLoadFromIff, sizeof(s_crashReportInfoLoadFromIff) - 1, "ObjectTemplate_Iff: %s\n", (filename && *filename) ? filename : "")); + s_crashReportInfoLoadFromIff[sizeof(s_crashReportInfoLoadFromIff) - 1] = '\0'; + + preLoad(); + load(iff); + postLoad(); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplate::preLoad() +{ +} + +// ---------------------------------------------------------------------- + +void ObjectTemplate::postLoad() +{ +} + +// ---------------------------------------------------------------------- + +void ObjectTemplate::saveToIff(Iff & /*iff*/) +{ + DEBUG_WARNING(true, ("ObjectTemplate::saveToIff - unsupported")); +} //lint !e1762 // (Info -- Member function 'ObjectTemplate::saveToIff(Iff &)' could be made const) // @todo Steve, this most likely is true. Save/write functions generally can be const since they're not modifying internal content. If this is true for you, please fix this function and all derived versions. + +//----------------------------------------------------------------------- + +const bool ObjectTemplate::isLoaded(const std::string & fileName) +{ + return ObjectTemplateList::isLoaded(fileName); +} + +// ---------------------------------------------------------------------- + +bool ObjectTemplate::derivesFrom (const std::string & potentialAncestorName) const +{ + if (!strcmp (getName (), potentialAncestorName.c_str ())) + return true; + + if (m_baseData) + return m_baseData->derivesFrom (potentialAncestorName); + + return false; +} + + +//---------------------------------------------------------------------- + +#ifdef _DEBUG +/** + * Special function used by datalint. Derived classes will check their data as + * needed. + */ +void ObjectTemplate::testValues(void) const +{ +} +#endif + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.h b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.h new file mode 100644 index 00000000..56e3a0bf --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplate.h @@ -0,0 +1,94 @@ +// ====================================================================== +// +// ObjectTemplate.h +// copyright 1999 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// Base class for ObjectTemplates +// +// ====================================================================== + +#ifndef INCLUDED_ObjectTemplate_H +#define INCLUDED_ObjectTemplate_H + +// ====================================================================== + +#include "sharedFoundation/DataResource.h" +#include "sharedFoundation/Tag.h" + +class Iff; +class Object; +class ServerObjectTemplate; +class SharedObjectTemplate; + +// ====================================================================== + +class ObjectTemplate : public DataResource +{ +public: + + static void install(); + + static Object *createObject(const char *fileName); + static const bool isLoaded(const std::string & fileName); + +public: + + explicit ObjectTemplate(const std::string &filename); + virtual ~ObjectTemplate() = 0; + + virtual ServerObjectTemplate * asServerObjectTemplate(); + virtual ServerObjectTemplate const * asServerObjectTemplate() const; + virtual SharedObjectTemplate * asSharedObjectTemplate(); + virtual SharedObjectTemplate const * asSharedObjectTemplate() const; + + void loadFromIff(Iff &iff); + void saveToIff(Iff &iff); + + const ObjectTemplate * getBaseTemplate(void) const; + + virtual Object *createObject() const; + virtual Tag getId() const = 0; + virtual void addReference() const; + virtual void releaseReference() const; + + bool derivesFrom (const std::string & potentialAncestorName) const; + +#ifdef _DEBUG +public: + // special code used by datalint + virtual void testValues(void) const; +#endif + +protected: + + virtual void release() const; + + virtual void preLoad(); + virtual void load(Iff &iff) = 0; + virtual void postLoad(); + +protected: + + // template to use as a base for this template + const ObjectTemplate *m_baseData; + +private: + + ObjectTemplate(const ObjectTemplate &); + ObjectTemplate &operator =(const ObjectTemplate &); +}; + + +// ====================================================================== + +inline const ObjectTemplate * ObjectTemplate::getBaseTemplate(void) const +{ + return m_baseData; +} + + +// ====================================================================== + + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.cpp b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.cpp new file mode 100644 index 00000000..4e45484b --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.cpp @@ -0,0 +1,202 @@ +// ====================================================================== +// +// ObjectTemplateList.cpp +// copyright 1999 Bootprint Entertainment +// copyright 2000 sonny online entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ObjectTemplateList.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/InstallTimer.h" +#include "sharedFile/TreeFile.h" +#include "sharedObject/ObjectTemplate.h" +#include "sharedObject/Object.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/CrcStringTable.h" +#include "sharedFoundation/DataResourceList.h" + +#include + +// ====================================================================== + +typedef DataResourceList ObjectTemplateListDataResourceList; + +template <> ObjectTemplateListDataResourceList::CreateDataResourceMap *ObjectTemplateListDataResourceList::ms_bindings = NULL; +template <> ObjectTemplateListDataResourceList::LoadedDataResourceMap *ObjectTemplateListDataResourceList::ms_loaded = NULL; + +namespace ObjectTemplateListNamespace +{ + bool ms_logLoadedObjectTemplates; + bool ms_logFetch; + CrcStringTable ms_crcStringTable; +} +using namespace ObjectTemplateListNamespace; + +// ====================================================================== + +void ObjectTemplateList::install(bool const loadObjectTemplateCrcStringTable) +{ + InstallTimer const installTimer("ObjectTemplateList::install"); + + ObjectTemplateListDataResourceList::install(); + + if (loadObjectTemplateCrcStringTable) + ms_crcStringTable.load("misc/object_template_crc_string_table.iff"); + + DebugFlags::registerFlag(ms_logLoadedObjectTemplates, "SharedObject/ObjectTemplateList", "logLoadedObjectTemplates", logLoadedObjectTemplates); + DebugFlags::registerFlag(ms_logFetch, "SharedObject/ObjectTemplateList", "logFetch"); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateList::remove() +{ + DebugFlags::unregisterFlag(ms_logLoadedObjectTemplates); + DebugFlags::unregisterFlag(ms_logFetch); + + ObjectTemplateListDataResourceList::remove(); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateList::registerTemplate(Tag id, CreateDataResourceFunc createFunc) +{ + ObjectTemplateListDataResourceList::registerTemplate(id, createFunc); +} + +// ---------------------------------------------------------------------- + +ObjectTemplateList::CreateDataResourceFunc ObjectTemplateList::assignBinding(Tag id, CreateDataResourceFunc createFunc) +{ + return ObjectTemplateListDataResourceList::assignBinding(id, createFunc); +} + +// ---------------------------------------------------------------------- + +ObjectTemplateList::CreateDataResourceFunc ObjectTemplateList::removeBinding(Tag id) +{ + return ObjectTemplateListDataResourceList::removeBinding(id); +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateList::logLoadedObjectTemplates() +{ + ObjectTemplateListDataResourceList::logLoadedResources("ObjectTemplates"); + ms_logLoadedObjectTemplates = false; +} + +// ---------------------------------------------------------------------- + +const ObjectTemplate *ObjectTemplateList::fetch(const std::string &filename) +{ + DEBUG_REPORT_LOG(ms_logFetch, ("[fetch] ObjectTemplateList::fetch: %s\n", filename.c_str())); + return ObjectTemplateListDataResourceList::fetch(filename); +} + +// ---------------------------------------------------------------------- + +const ObjectTemplate *ObjectTemplateList::fetch(const char *filename) +{ + DEBUG_REPORT_LOG(ms_logFetch, ("[fetch] ObjectTemplateList::fetch: %s\n", filename)); + return ObjectTemplateListDataResourceList::fetch(filename); +} + +// ---------------------------------------------------------------------- + +const ObjectTemplate *ObjectTemplateList::fetch(Iff &source) +{ + return ObjectTemplateListDataResourceList::fetch(source); +} + +// ---------------------------------------------------------------------- + +const ObjectTemplate *ObjectTemplateList::fetch(const CrcString &filename) +{ + DEBUG_REPORT_LOG(ms_logFetch, ("[fetch] ObjectTemplateList::fetch: %s\n", filename.getString())); + return ObjectTemplateListDataResourceList::fetch(filename); +} + +// ---------------------------------------------------------------------- + +const ObjectTemplate *ObjectTemplateList::fetch(uint32 crc) +{ + return ObjectTemplateListDataResourceList::fetch(lookUp(crc)); +} + +// ---------------------------------------------------------------------- + +Object *ObjectTemplateList::createObject (const CrcString &fileName) +{ + const ObjectTemplate *objectTemplate = fetch(fileName.getString()); + if (!objectTemplate) + return 0; + + Object* const object = objectTemplate->createObject(); + objectTemplate->releaseReference(); + + return object; +} + +// ---------------------------------------------------------------------- + +void ObjectTemplateList::release(const ObjectTemplate &dataResource) +{ + ObjectTemplateListDataResourceList::release(dataResource); +} + +// ---------------------------------------------------------------------- + +ObjectTemplate *ObjectTemplateList::reload(Iff &source) +{ + return ObjectTemplateListDataResourceList::reload(source); +} + +//----------------------------------------------------------------------- + +bool ObjectTemplateList::isLoaded(const std::string &fileName) +{ + return ObjectTemplateListDataResourceList::isLoaded(fileName); +} + +//---------------------------------------------------------------------- + +void ObjectTemplateList::loadCrcStringTable(const char *fileName) +{ + ms_crcStringTable.load(fileName); +} + +//---------------------------------------------------------------------- + +ConstCharCrcString const ObjectTemplateList::lookUp(const char * string) +{ + ConstCharCrcString result = ms_crcStringTable.lookUp(string); + WARNING(result.isEmpty(), ("ObjectTemplateList::lookUp objectTemplate %s not found in table", string)); + return result; +} + +//---------------------------------------------------------------------- + +ConstCharCrcString const ObjectTemplateList::lookUp(uint32 crc) +{ + return ms_crcStringTable.lookUp(crc); +} + +//---------------------------------------------------------------------- + +void ObjectTemplateList::garbageCollect () +{ + ObjectTemplateListDataResourceList::garbageCollect (); +} + +//---------------------------------------------------------------------- + +void ObjectTemplateList::getAllTemplateNamesFromCrcStringTable(stdvector::fwd & objectTemplateNames) +{ + ms_crcStringTable.getAllStrings(objectTemplateNames); +} + +//---------------------------------------------------------------------- diff --git a/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.h b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.h new file mode 100644 index 00000000..b8ce421a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ObjectTemplateList.h @@ -0,0 +1,79 @@ +// ====================================================================== +// +// ObjectTemplateList.h +// copyright 1999 Bootprint Entertainment +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_ObjectTemplateList_H +#define INCLUDED_ObjectTemplateList_H + +// ====================================================================== + +#include "sharedFoundation/Tag.h" + +class ConstCharCrcString; +class CrcString; +class CrcStringTable; +class Iff; +class Object; +class ObjectTemplate; + +// ====================================================================== + +class ObjectTemplateList +{ + friend class ObjectTemplate; + +public: + + typedef ObjectTemplate *(*CreateDataResourceFunc)(const std::string &filename); + +public: + + static void install(bool loadObjectTemplateCrcStringTable); + static void remove(); + + static void logLoadedObjectTemplates(); + + // functions to create a new DataResource + static const ObjectTemplate *fetch(Iff &source); + static const ObjectTemplate *fetch(const CrcString &filename); + static const ObjectTemplate *fetch(uint32 crc); + static const ObjectTemplate *fetch(const std::string &filename); + static const ObjectTemplate *fetch(const char *filename); + static Object *createObject (const CrcString &fileName); + static bool isLoaded(const std::string &fileName); + + // function to reload a data resource with new data + static ObjectTemplate *reload(Iff &source); + + static void registerTemplate(Tag id, CreateDataResourceFunc createFunc); + static CreateDataResourceFunc assignBinding(Tag id, CreateDataResourceFunc createFunc); + static CreateDataResourceFunc removeBinding(Tag tag); + + // CrcStringTable functions + static void loadCrcStringTable(const char *fileName); + static ConstCharCrcString const lookUp(const char * string); + static ConstCharCrcString const lookUp(uint32 crc); + + static void garbageCollect (); + + static void getAllTemplateNamesFromCrcStringTable(stdvector::fwd & objectTemplateNames); + +private: + + static void release(const ObjectTemplate &dataResource); + +private: + + ObjectTemplateList(); + ~ObjectTemplateList(); + ObjectTemplateList(const ObjectTemplateList &); + ObjectTemplateList &operator =(const ObjectTemplateList &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/object/ScheduleData.cpp b/engine/shared/library/sharedObject/src/shared/object/ScheduleData.cpp new file mode 100644 index 00000000..8de48b15 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ScheduleData.cpp @@ -0,0 +1,50 @@ +// ====================================================================== +// +// ScheduleData.cpp +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/ScheduleData.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" + +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITH_INSTALL(ScheduleData, true, 0, 0, 0); + +// ====================================================================== + +ScheduleData::ScheduleData(AlterScheduler::ScheduleTime initialMostRecentAlterTime): + m_mostRecentAlterTime(initialMostRecentAlterTime), + m_alterNowNext(NULL), + m_alterNowPrevious(NULL), + m_alterNextFrameNext(NULL), + m_alterNextFramePrevious(NULL), + m_concludeNext(NULL), + m_concludePrevious(NULL), + m_scheduleTimeMapIterator(), + m_schedulePhase(0) +{ +} + +// ---------------------------------------------------------------------- + +ScheduleData::~ScheduleData() +{ + DEBUG_WARNING(m_alterNowNext || m_alterNowPrevious, ("ScheduleData for owning object is still in the AlterScheduler AlterNow list, improper object cleanup.")); + DEBUG_WARNING(m_alterNextFrameNext || m_alterNextFramePrevious, ("ScheduleData for owning object is still in the AlterScheduler AlterNextFrame list, improper object cleanup.")); + DEBUG_WARNING(m_concludeNext || m_concludePrevious, ("ScheduleData for owning object is still in the AlterScheduler Conclude list, improper object cleanup.")); + DEBUG_WARNING(AlterScheduler::isIteratorInScheduleTimeMap(&m_scheduleTimeMapIterator), ("ScheduleData for owning object is still in the AlterScheduler ScheduleTimeMap, improper object cleanup.")); + DEBUG_FATAL(m_alterNowNext || m_alterNowPrevious + || m_alterNextFrameNext || m_alterNextFramePrevious + || m_concludeNext || m_concludePrevious + || AlterScheduler::isIteratorInScheduleTimeMap(&m_scheduleTimeMapIterator), + ("ScheduleData not cleaned up properly, referring object not removed from alter scheduler.")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, m_schedulePhase, AS_MAX_SCHEDULE_PHASE_COUNT); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/object/ScheduleData.h b/engine/shared/library/sharedObject/src/shared/object/ScheduleData.h new file mode 100644 index 00000000..4942302a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/object/ScheduleData.h @@ -0,0 +1,203 @@ +// ====================================================================== +// +// ScheduleData.h +// Copyright 2003 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_ScheduleData_H +#define INCLUDED_ScheduleData_H + +// ====================================================================== + +#include "sharedObject/AlterScheduler.h" +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include + +// ====================================================================== + +class ScheduleData +{ + MEMORY_BLOCK_MANAGER_INTERFACE_WITH_INSTALL; + +public: + + explicit ScheduleData(AlterScheduler::ScheduleTime initialMostRecentAlterTime); + ~ScheduleData(); + + void setMostRecentAlterTime(AlterScheduler::ScheduleTime scheduleTime); + AlterScheduler::ScheduleTime getMostRecentAlterTime(); + + Object *getAlterNowNext(); + Object *getAlterNowPrevious(); + + void setAlterNowNext(Object *object); + void setAlterNowPrevious(Object *object); + + Object *getAlterNextFrameNext(); + Object *getAlterNextFramePrevious(); + + void setAlterNextFrameNext(Object *object); + void setAlterNextFramePrevious(Object *object); + + Object *getConcludeNext(); + Object *getConcludePrevious(); + + void setConcludeNext(Object *object); + void setConcludePrevious(Object *object); + + AlterScheduler::ScheduleTimeMap::iterator &getScheduleTimeMapIterator(); + + int getSchedulePhase() const; + void setSchedulePhase(int schedulePhase); + +private: + + // Disabled. + ScheduleData(); + ScheduleData(ScheduleData const&); + ScheduleData &operator =(ScheduleData const&); + +private: + + AlterScheduler::ScheduleTime m_mostRecentAlterTime; + + Object *m_alterNowNext; + Object *m_alterNowPrevious; + + Object *m_alterNextFrameNext; + Object *m_alterNextFramePrevious; + + Object *m_concludeNext; + Object *m_concludePrevious; + + AlterScheduler::ScheduleTimeMap::iterator m_scheduleTimeMapIterator; + + int m_schedulePhase; + +}; + +// ====================================================================== + +inline void ScheduleData::setMostRecentAlterTime(AlterScheduler::ScheduleTime scheduleTime) +{ + m_mostRecentAlterTime = scheduleTime; +} + +// ---------------------------------------------------------------------- + +inline AlterScheduler::ScheduleTime ScheduleData::getMostRecentAlterTime() +{ + return m_mostRecentAlterTime; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getAlterNowNext() +{ + return m_alterNowNext; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getAlterNowPrevious() +{ + return m_alterNowPrevious; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setAlterNowNext(Object *object) +{ + m_alterNowNext = object; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setAlterNowPrevious(Object *object) +{ + m_alterNowPrevious = object; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getAlterNextFrameNext() +{ + return m_alterNextFrameNext; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getAlterNextFramePrevious() +{ + return m_alterNextFramePrevious; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setAlterNextFrameNext(Object *object) +{ + m_alterNextFrameNext = object; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setAlterNextFramePrevious(Object *object) +{ + m_alterNextFramePrevious = object; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getConcludeNext() +{ + return m_concludeNext; +} + +// ---------------------------------------------------------------------- + +inline Object *ScheduleData::getConcludePrevious() +{ + return m_concludePrevious; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setConcludeNext(Object *object) +{ + m_concludeNext = object; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setConcludePrevious(Object *object) +{ + m_concludePrevious = object; +} + +// ---------------------------------------------------------------------- + +inline AlterScheduler::ScheduleTimeMap::iterator &ScheduleData::getScheduleTimeMapIterator() +{ + return m_scheduleTimeMapIterator; +} + +// ---------------------------------------------------------------------- + +inline int ScheduleData::getSchedulePhase() const +{ + return m_schedulePhase; +} + +// ---------------------------------------------------------------------- + +inline void ScheduleData::setSchedulePhase(int schedulePhase) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, schedulePhase, AS_MAX_SCHEDULE_PHASE_COUNT); + m_schedulePhase = schedulePhase; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/CellProperty.cpp b/engine/shared/library/sharedObject/src/shared/portal/CellProperty.cpp new file mode 100644 index 00000000..27678d75 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/CellProperty.cpp @@ -0,0 +1,1303 @@ +// ====================================================================== +// +// CellProperty.cpp +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CellProperty.h" + +#include "sharedCollision/ConfigSharedCollision.h" +#include "sharedCollision/DoorObject.h" +#include "sharedCollision/Floor.h" +#include "sharedCollision/FloorMesh.h" +#include "sharedCollision/FloorManager.h" +#include "sharedCollision/BaseExtent.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedMath/DebugShapeRenderer.h" +#include "sharedMath/Sphere.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectNotification.h" +#include "sharedObject/Portal.h" +#include "sharedObject/PortalPropertyTemplate.h" +#include "sharedUtility/Location.h" + +#include +#include + +// ====================================================================== + +const Tag TAG_CELP = TAG(C,E,L,P); + +// ====================================================================== + +namespace CellPropertyNamespace +{ + class Notification : public ObjectNotification + { + public: + + static void setPortalTransitionsEnabled(bool enabled); + + public: + + Notification(); + virtual ~Notification(); + + virtual int getPriority() const; + + virtual bool positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + virtual bool positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + + private: + + static bool ms_enabled; + + private: + + Notification(const Notification &); //lint -esym(754, Notification::Notification) // (Info -- local structure member 'Notification::Notification(const CellPropertyNamespace::Notification &)' not referenced) // defensive hiding + Notification &operator =(const Notification &); + }; + + float const ms_maximumValidCellSpaceCoordinate = 1024.0f; + + Object *ms_worldCellObject; + Notification ms_portalCrossingNotification; + bool ms_renderPortals; + CellProperty::CreateDpvsCellHookFunction ms_createDpvsCellHookFunction = NULL; + CellProperty::DestroyDpvsCellHookFunction ms_destroyDpvsCellHookFunction = NULL; + CellProperty::AddToRenderWorldHookFunction ms_addToRenderWorldHook = NULL; + + CellProperty::PolyAppearanceFactory ms_portalBarrierFactory = NULL; + CellProperty::PolyAppearanceFactory ms_forceFieldFactory = NULL; + + CellProperty::AccessAllowedHookFunction ms_accessAllowedHookFunction = NULL; +} +using namespace CellPropertyNamespace; + +// ====================================================================== + +bool CellPropertyNamespace::Notification::ms_enabled = true; + +CellProperty *CellProperty::ms_worldCellProperty; +CellProperty::TextureFetch CellProperty::ms_textureFetch = NULL; +CellProperty::TextureRelease CellProperty::ms_textureRelease = NULL; +CellProperty::DeleteVisibleCellProperty CellProperty::ms_deleteVisibleCellProperty = NULL; + +// ====================================================================== + +CellPropertyNamespace::Notification::Notification() : + ObjectNotification() +{ +} + +// ---------------------------------------------------------------------- + +CellPropertyNamespace::Notification::~Notification() +{ +} + +// ---------------------------------------------------------------------- + +int CellPropertyNamespace::Notification::getPriority() const +{ + return -100; +} + +// ---------------------------------------------------------------------- + +bool CellPropertyNamespace::Notification::positionChanged(Object &object, bool const dueToParent, const Vector &oldPosition_p) const +{ + if (!ms_enabled) + return true; + + // If this notification is due to our parent, we don't need to continue + if (dueToParent) + return true; + + // If we're attached to an object and we're not attached to a cell, we don't need to continue + if (object.getAttachedTo() && !object.getAttachedTo()->getCellProperty()) + return true; + + Vector start = object.getTransform_p2w().rotateTranslate_l2p(oldPosition_p); + Vector end = object.getPosition_w(); + + if (start == end) + return true; + + // Move the old and new position up by half a meter so that our line-portal intersection test + // doesn't miss the bottom of the portal. + + //@todo - This assumes that the position we're getting for the creature is at the creature's feet, + // that Y is up, and that moving the position up will put it closer to the center of the portal + + // This is intended to fix problems with entering buildings whose doorway portals sit right on the + // terrain - slight variations in the height of the terrain can cause the creature's position to slide + // under the portal instead of going through it. + + // The assumption that y is up does not hold in space, so we need to do our correction in the actual + // up direction of the cell. + Vector objUpW = object.getObjectFrameJ_w(); + objUpW *= 0.1f; + start += objUpW; + end += objUpW; + + CellProperty *targetCell = NULL; + + CellProperty *lastCell = NULL; + CellProperty *currentCell = object.getParentCell(); + + while(currentCell) + { + Vector const cellStart = currentCell->getOwner().rotateTranslate_w2o(start); + Vector const cellEnd = currentCell->getOwner().rotateTranslate_w2o(end); + + float time = 0.0f; + CellProperty *nextCell = currentCell->getDestinationCell(cellStart, cellEnd, time); + + if(time == 1.0f) break; + + if(nextCell == NULL) break; + if(nextCell == currentCell) break; + if(nextCell == lastCell) break; + + lastCell = currentCell; + currentCell = nextCell; + + targetCell = currentCell; + + start = Vector::linearInterpolate(start, end, time); + } + + if (targetCell) + { + // object changed portals, don't continue with this position change because the cell change will handle all that as well + object.setParentCell(targetCell); + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool CellPropertyNamespace::Notification::positionAndRotationChanged(Object &object, bool /* dueToParent */, const Vector &oldPosition) const +{ + return positionChanged(object, false, oldPosition); +} + +// ---------------------------------------------------------------------- + +void CellPropertyNamespace::Notification::setPortalTransitionsEnabled(bool enabled) +{ + ms_enabled = enabled; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setTextureHookFunctions(TextureFetch textureFetch, TextureRelease textureRelease) +{ + ms_textureFetch = textureFetch; + ms_textureRelease = textureRelease; + +} + +// ---------------------------------------------------------------------- + +void CellProperty::setDeleteVisibleCellProperty(DeleteVisibleCellProperty deleteVisibleCellProperty) +{ + ms_deleteVisibleCellProperty = deleteVisibleCellProperty; +} + +// ====================================================================== + +void CellProperty::install() +{ + ms_worldCellObject = new Object(); + ms_worldCellProperty = new CellProperty(*ms_worldCellObject); + ms_worldCellProperty->m_cellIndex = 0; + ms_worldCellProperty->m_cellName = "world"; + ms_worldCellProperty->m_cellNameCrc = Crc::normalizeAndCalculate(ms_worldCellProperty->m_cellName); + ms_worldCellObject->addProperty(*ms_worldCellProperty); + ExitChain::add(&remove, "CellProperty::remove"); + + DebugFlags::registerFlag( ms_renderPortals, "SharedObject", "renderPortals" ); +} + +// ---------------------------------------------------------------------- + +void CellProperty::remove() +{ + delete ms_worldCellObject; + ms_worldCellObject = NULL; + ms_worldCellProperty = NULL; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setAddToRenderWorldHook( AddToRenderWorldHookFunction hook ) +{ + ms_addToRenderWorldHook = hook; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setPortalBarrierFactory ( PolyAppearanceFactory factory ) +{ + ms_portalBarrierFactory = factory; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setForceFieldFactory ( PolyAppearanceFactory factory ) +{ + ms_forceFieldFactory = factory; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setAccessAllowedHookFunction(AccessAllowedHookFunction hook) +{ + ms_accessAllowedHookFunction = hook; +} + +// ---------------------------------------------------------------------- + +void CellProperty::addToRenderWorld (Object & object) +{ + if (ms_addToRenderWorldHook) + ms_addToRenderWorldHook(object); +} + +// ---------------------------------------------------------------------- + +Appearance *CellProperty::createPortalBarrier(VertexList const & verts, const VectorArgb &color) +{ + if (ms_portalBarrierFactory) + return ms_portalBarrierFactory(verts,color); + + return NULL; +} + +// ---------------------------------------------------------------------- + +Appearance *CellProperty::createForceField(VertexList const & verts, const VectorArgb &color) +{ + if (ms_forceFieldFactory) + return ms_forceFieldFactory(verts,color); + + return NULL; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setCreateAndDestroyDpvsCellHookFunctions(CreateDpvsCellHookFunction createDpvsCellHookFunction, DestroyDpvsCellHookFunction destroyDpvsCellHookFunction) +{ + ms_createDpvsCellHookFunction = createDpvsCellHookFunction; + ms_destroyDpvsCellHookFunction = destroyDpvsCellHookFunction; +} + +// ---------------------------------------------------------------------- + +CellProperty *CellProperty::getWorldCellProperty() +{ + return ms_worldCellProperty; +} + +// ---------------------------------------------------------------------- + +PropertyId CellProperty::getClassPropertyId() +{ + return PROPERTY_HASH(CellProperty, 0x9C3DFF88); +} + +// ---------------------------------------------------------------------- + +void CellProperty::addPortalCrossingNotification(Object &object) +{ + object.addNotification(ms_portalCrossingNotification); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removePortalCrossingNotification(Object &object) +{ + object.removeNotification(ms_portalCrossingNotification); +} + +// ---------------------------------------------------------------------- + +void CellProperty::setPortalTransitionsEnabled(bool enabled) +{ + Notification::setPortalTransitionsEnabled(enabled); +} + +// ====================================================================== + +CellProperty::CellProperty(Object &owner) +: Container(getClassPropertyId(), owner), + m_portalProperty(NULL), + m_cellIndex(-1), + m_appearanceObject(NULL), + m_portalObjectList(new PortalObjectList), + m_visible(false), + m_floor(NULL), + m_cellName(NULL), + m_cellNameCrc(0), + m_dpvsCell(NULL), + m_environmentTexture(NULL), + m_fogEnabled(false), + m_fogColor(0), + m_fogDensity(0.f), + m_appliedInteriorLayout(false), + m_preVisibilityTraversalRenderHookFunctionList(NULL), + m_enterRenderHookFunctionList(NULL), + m_preDrawRenderHookFunctionList(NULL), + m_exitRenderHookFunctionList(NULL) +{ + if (ms_createDpvsCellHookFunction) + m_dpvsCell = (*ms_createDpvsCellHookFunction)(this); +} + +// ---------------------------------------------------------------------- + +CellProperty::~CellProperty() +{ + DEBUG_FATAL(this != ms_worldCellProperty && m_portalObjectList->size() > 1, ("CellProperty is still attached")); + DEBUG_FATAL(this == ms_worldCellProperty && m_portalObjectList->size() > 0, ("Other CellProperties are still attached to world")); + + if (m_visible && ms_deleteVisibleCellProperty) + (*ms_deleteVisibleCellProperty)(this); + + if (m_environmentTexture) + { + NOT_NULL(ms_textureRelease); + ms_textureRelease(m_environmentTexture); + m_environmentTexture = NULL; + } + + if (!m_portalObjectList->empty()) + { + PortalList *portalList = m_portalObjectList->front().portalList; + PortalList::iterator iEnd = portalList->end(); + for (PortalList::iterator i = portalList->begin(); i != iEnd; ++i) + delete *i; + delete portalList; + } + + m_portalProperty = NULL; + delete m_appearanceObject; + delete m_portalObjectList; + delete m_floor; + m_cellName = NULL; + m_cellNameCrc = 0; + + if (m_dpvsCell) + { + NOT_NULL(ms_destroyDpvsCellHookFunction); + (*ms_destroyDpvsCellHookFunction)(m_dpvsCell); + m_dpvsCell = NULL; + } + + delete m_preVisibilityTraversalRenderHookFunctionList; + delete m_enterRenderHookFunctionList; + delete m_preDrawRenderHookFunctionList; + delete m_exitRenderHookFunctionList; +} + +// ---------------------------------------------------------------------- + +void CellProperty::initialize(const PortalProperty &portalProperty, int cellIndex, bool createAppearance) +{ + m_portalProperty = &portalProperty; + const PortalPropertyTemplateCell &cellTemplate = portalProperty.getPortalPropertyTemplate().getCell(cellIndex); + + PortalObjectEntry poe; + poe.portalProperty = &portalProperty; + poe.portalList = cellTemplate.createPortalList(this, &getOwner()); + poe.attached = false; + m_portalObjectList->push_back(poe); + + if (createAppearance) + { + DEBUG_FATAL(m_appearanceObject, ("appearance already created")); + m_appearanceObject = new Object; + m_appearanceObject->setDebugName("Cell appearance object"); + m_appearanceObject->attachToObject_p(&getOwner(), true); + Appearance * const appearance = AppearanceTemplateList::createAppearance(cellTemplate.getAppearanceName()); + appearance->setShadowBlobAllowed(); + m_appearanceObject->setAppearance(appearance); + + if (ms_addToRenderWorldHook) + ms_addToRenderWorldHook(*m_appearanceObject); + } + + // ---------- + // If this cell has a floor, try and load the floor mesh + + if (cellTemplate.getFloorName()) + { + m_floor = FloorManager::createFloor(cellTemplate.getFloorName(),&getOwner(),NULL,false); + WARNING(!m_floor, ("Cell %s could not load floor %s", cellTemplate.getAppearanceName(), cellTemplate.getFloorName())); + } + else + { + WARNING(true, ("Cell %s has no floor", cellTemplate.getAppearanceName())); + } + + m_cellIndex = cellIndex; + m_cellName = cellTemplate.getName(); + m_cellNameCrc = Crc::normalizeAndCalculate(m_cellName); +} + +// ---------------------------------------------------------------------- + +int CellProperty::depersistContents(const Object& item) +{ + setPortalTransitionsEnabled(false); + Transform t = item.getTransform_o2p(); + const_cast(item).setParentCell(this); + const_cast(item).setTransform_o2p(t); + setPortalTransitionsEnabled(true); + + return Container::depersistContents(item); +} + +// ---------------------------------------------------------------------- + +bool CellProperty::internalItemRemoved(const Object& item) +{ + //-- HACK: the client should just chain up + { + if (ms_createDpvsCellHookFunction) + return Container::internalItemRemoved(item); + } + + if (Container::internalItemRemoved(item)) + { + if (item.getAttachedTo()) + const_cast(item).detachFromObject(Object::DF_parent); + + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::mayAdd(const Object & object, ContainerErrorCode& error) const +{ + bool retval = (getOwner().isAuthoritative() == object.isAuthoritative()); + error = retval ? CEC_Success : CEC_NoPermission; + + return retval; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::remove(Object &item, ContainerErrorCode& error) +{ + if (Container::remove(item, error)) + { + item.Object::setParentCell(getWorldCellProperty()); + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::remove(ContainerIterator &pos, ContainerErrorCode& error) +{ + Object *item = (*pos).getObject(); + if (Container::remove(pos, error) && item) + { + item->detachFromObject(Object::DF_parent); + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::isWorldCell() const +{ + return this == ms_worldCellProperty; +} + +// ---------------------------------------------------------------------- + +int CellProperty::getTypeId() const +{ + return static_cast(TAG_CELP); +} + +// ---------------------------------------------------------------------- + +void CellProperty::debugPrint(std::string &buffer) const +{ + char tempBuffer[1024]; + + buffer += "====[BEGIN: cell property]====\n"; + + sprintf(tempBuffer, "container id [%s].\n", getOwner().getNetworkId().getValueString().c_str()); + buffer += tempBuffer; + + buffer += "embedding container contents now:\n"; + Container::debugPrint(buffer); + + buffer += "====[END: cell property]====\n"; +} + +// ---------------------------------------------------------------------- + +void CellProperty::removeFromWorld() +{ + Container::removeFromWorld(); + + if (!m_portalObjectList->empty()) + { + PortalList *portalList = m_portalObjectList->front().portalList; + PortalList::iterator iEnd = portalList->end(); + + for (PortalList::iterator i = portalList->begin(); i != iEnd; ++i) + { + Portal * const portal = *i; + portal->removeFromDpvs(); + } + } + + m_appliedInteriorLayout = false; +} + +// ---------------------------------------------------------------------- + +int CellProperty::getPortalCount() const +{ + int counter = 0; + + const PortalObjectList::const_iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::const_iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + { + const PortalList &portalList = *i->portalList; + + counter += static_cast(portalList.size()); + } + + return counter; +} + +// ---------------------------------------------------------------------- + +Object *CellProperty::getAppearanceObject() +{ + return m_appearanceObject; +} + +// ---------------------------------------------------------------------- + +const Object *CellProperty::getAppearanceObject() const +{ + NOT_NULL(m_appearanceObject); + return m_appearanceObject; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::areAdjacent(const CellProperty *cellProperty1, const CellProperty *cellProperty2) +{ + bool result = false; + + if ( (cellProperty1 != NULL) + && (cellProperty2 != NULL)) + { + if (cellProperty1 == cellProperty2) + { + // Same cell property means they are adjacent + + result = true; + } + else if ( (cellProperty1 != getWorldCellProperty()) + && (cellProperty2 != getWorldCellProperty()) + && (cellProperty1->getPortalProperty() != cellProperty2->getPortalProperty())) + { + // Both cell properties are not the world cell property and + // they do not share the same portal property + + result = false; + } + else if ( (cellProperty1->m_portalObjectList != NULL) + && (cellProperty2->m_portalObjectList != NULL)) + { + // Pick the list that is not the world cell property, or the + // smallest list + + PortalObjectList *portalObjectList = cellProperty1->m_portalObjectList; + CellProperty const *checkCellProperty = cellProperty2; + + if ( (cellProperty1 == getWorldCellProperty()) + || ((cellProperty2 != getWorldCellProperty()) + && (cellProperty1->m_portalObjectList->size() > cellProperty2->m_portalObjectList->size()))) + { + portalObjectList = cellProperty2->m_portalObjectList; + checkCellProperty = cellProperty1; + } + + if (portalObjectList != NULL) + { + //DEBUG_REPORT_LOG((portalObjectList->size() > 1), ("Portal Object List > 1 - size: %d", portalObjectList->size())); + + PortalObjectList::const_iterator iterPortalObjectList = portalObjectList->begin(); + + for (; iterPortalObjectList != portalObjectList->end(); ++iterPortalObjectList) + { + // Check all the portals in this portal object + + const PortalList &portalList = *(iterPortalObjectList->portalList); + + PortalList::const_iterator iterPortalList = portalList.begin(); + + for (; iterPortalList != portalList.end(); ++iterPortalList) + { + // See if the cell property we are looking for is on the + // other side of any of the portals + + const Portal * const portal = (*iterPortalList); + const CellProperty * const cellProperty = portal->getNeighbor()->getParentCell(); + + if (cellProperty == checkCellProperty) + { + result = true; + break; + } + } + } + } + } + } + + return result; +} + +// ---------------------------------------------------------------------- + +float CellProperty::getMaximumValidCellSpaceCoordinate() +{ + return ms_maximumValidCellSpaceCoordinate; +} + +// ---------------------------------------------------------------------- + +void CellProperty::releaseWorldCellPropertyEnvironmentTexture() +{ + if (ms_worldCellProperty) + ms_worldCellProperty->setEnvironmentTexture(0); +} + +// ---------------------------------------------------------------------- +/** + * Check line segment for portal crossing. + * + * @param startPosition Starting position, in the space of this cell. + * @param endPosition Ending position, in the space of this cell. + * @return The CellProperty that an object traversing the object is in. Will return NULL if remaining in this cell. + */ + +CellProperty *CellProperty::getDestinationCell(const Vector &startPosition, const Vector &endPosition, float &closestPortalT, bool passableOnly) const +{ + CellProperty *cellProperty = 0; + closestPortalT = FLT_MAX; + +#if 0 + if ((startPosition - endPosition).magnitude() > 2.0f) + { + static volatile int debug = 0; + ++debug; + } +#endif + + const PortalObjectList::const_iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::const_iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + { + const Object &portalObject = i->portalProperty->getOwner(); + const PortalList &portalList = *i->portalList; + + const PortalList::const_iterator jEnd = portalList.end(); + for (PortalList::const_iterator j = portalList.begin(); j != jEnd; ++j) + { + const Portal *portal = *j; + + if (passableOnly && !portal->isPassable()) + continue; + + float t = FLT_MAX; + bool penetrated = true; + + if (i->attached) + { + const Vector b = portalObject.rotateTranslate_w2o(getOwner().rotateTranslate_o2w(startPosition)); + const Vector e = portalObject.rotateTranslate_w2o(getOwner().rotateTranslate_o2w(endPosition)); + penetrated = portal->testPenetration(b, e, t); + } + else + { + penetrated = portal->testPenetration(startPosition, endPosition, t); + } + + if (penetrated && t <= closestPortalT) + { + closestPortalT = t; + cellProperty = portal->getNeighbor() ? portal->getNeighbor()->getParentCell() : 0; + } + } + } + + return cellProperty; +} + +// ---------------------------------------------------------------------- + +CellProperty *CellProperty::getDestinationCell(const Object *object, int portalId) const +{ + if(portalId < 0) return NULL; + if(object == NULL) return NULL; + + const PortalObjectList::const_iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::const_iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + { + const Object &portalObject = i->portalProperty->getOwner(); + const PortalList &portalList = *i->portalList; + + if(this == CellProperty::getWorldCellProperty()) + { + // We only want to check the list of portals for this cell object + if(&portalObject != object) continue; + } + else + { + if(i->portalProperty != m_portalProperty) continue; + } + + if(portalId >= static_cast(portalList.size())) + { + DEBUG_WARNING(true,("CellProperty::getDestinationCell(portalId) - tried to get an invalid portal\n")); + + return NULL; + } + + return portalList[static_cast(portalId)]->getNeighbor()->getParentCell(); + } + + return NULL; +} + +// ---------------------------------------------------------------------- +// Return the set of portals the sphere goes through + +bool CellProperty::getDestinationCells(const Sphere &sphere, std::vector & outCells) const +{ + bool hitPortal = false; + + Sphere testSphere = sphere; + + const PortalObjectList::const_iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::const_iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + { + const Object &portalObject = i->portalProperty->getOwner(); + const PortalList &portalList = *i->portalList; + + if (i->attached) + { + testSphere.setCenter( portalObject.rotateTranslate_w2o(getOwner().rotateTranslate_o2w(sphere.getCenter())) ); + } + else + { + testSphere.setCenter( sphere.getCenter() ); + } + + const PortalList::const_iterator jEnd = portalList.end(); + for (PortalList::const_iterator j = portalList.begin(); j != jEnd; ++j) + { + const Portal *portal = *j; + + if(portal->testOverlap(testSphere)) + { + hitPortal = true; + + const Portal *neighbor = portal->getNeighbor(); + + WARNING(neighbor == NULL,("CellProperty::getDestinationCells - Cell %s has a portal without a neighbor\n",getOwner().getNetworkId().getValueString().c_str())); + + if(neighbor) + { + CellProperty *neighborCell = neighbor->getParentCell(); + + if(neighborCell) + { + outCells.push_back(neighborCell); + } + } + } + } + } + + return hitPortal; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::isAdjacentTo(const CellProperty *cell) const +{ + if(this == cell) return true; + + if(cell == NULL) return false; + + // ---------- + + const PortalObjectList::const_iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::const_iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + { + const PortalList &portalList = *i->portalList; + + const PortalList::const_iterator jEnd = portalList.end(); + for (PortalList::const_iterator j = portalList.begin(); j != jEnd; ++j) + { + const Portal *portal = *j; + + CellProperty const * const neighbor = portal->getNeighbor() ? portal->getNeighbor()->getParentCell() : 0; + if (neighbor == cell) + return true; + } + } + + // ---------- + + return false; +} + +// ---------------------------------------------------------------------- + +void CellProperty::attach(const PortalProperty &portalProperty, PortalList *portalList) +{ + PortalObjectEntry poe; + poe.portalProperty = &portalProperty; + poe.portalList = portalList; + poe.attached = true; + m_portalObjectList->push_back(poe); +} + +// ---------------------------------------------------------------------- + +void CellProperty::detach(const PortalProperty &portalProperty) +{ + const PortalObjectList::iterator iEnd = m_portalObjectList->end(); + for (PortalObjectList::iterator i = m_portalObjectList->begin(); i != iEnd; ++i) + if (i->portalProperty == &portalProperty) + { + PortalList *portalList = i->portalList; + PortalList::iterator jEnd = portalList->end(); + for (PortalList::iterator j = portalList->begin(); j != jEnd; ++j) + delete *j; + + delete portalList; + IGNORE_RETURN(m_portalObjectList->erase(i)); + return; + } + + DEBUG_FATAL(true, ("could not find attached portal object")); +} + +// ---------------------------------------------------------------------- + +void CellProperty::addObject_w(Object &object) +{ + // This is the ONLY TIME that we should be explicitly calling Object::setParentCell - + // normally the client should call setParentCell virtually, and the server should always + // go through ContainerInterface::transferItemToCell + object.Object::setParentCell(this); + + + if (!isWorldCell()) + { + ContainerErrorCode tmp = CEC_Success; + IGNORE_RETURN(addToContents(object, tmp)); + } + else + DEBUG_WARNING(true, ("attempting to add object %s to world cell", object.getNetworkId().getValueString().c_str())); +} + +// ---------------------------------------------------------------------- + +Floor *CellProperty::getFloor() +{ + return m_floor; +} + +// ---------------------------------------------------------------------- + +const Floor *CellProperty::getFloor() const +{ + return m_floor; +} + +// ---------------------------------------------------------------------- + +const BaseExtent *CellProperty::getCollisionExtent() const +{ + if(m_portalProperty) + { + return m_portalProperty->getPortalPropertyTemplate().getCell(m_cellIndex).getCollisionExtent(); + } + else + { + return NULL; + } +} + +// ---------------------------------------------------------------------- + +const BaseClass *CellProperty::getPathGraph() const +{ + if(m_floor) + { + FloorMesh const * floorMesh = m_floor->getFloorMesh(); + + if(floorMesh) + { + return floorMesh->getPathGraph(); + } + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +void CellProperty::addHookFunction(RenderHookFunctionList *&renderHookFunctionList, RenderHookFunction renderHookFunction) const +{ + if (!renderHookFunctionList) + renderHookFunctionList = new RenderHookFunctionList; + + DEBUG_FATAL(std::find(renderHookFunctionList->begin(), renderHookFunctionList->end(), renderHookFunction) != renderHookFunctionList->end(), ("Hook function already present")); + renderHookFunctionList->push_back(renderHookFunction); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removeHookFunction(RenderHookFunctionList *const &renderHookFunctionList, RenderHookFunction renderHookFunction) const +{ + NOT_NULL(renderHookFunctionList); + + RenderHookFunctionList::iterator i = std::find(renderHookFunctionList->begin(), renderHookFunctionList->end(), renderHookFunction); + DEBUG_FATAL(i == renderHookFunctionList->end(), ("Hook function not present")); + IGNORE_RETURN(renderHookFunctionList->erase(i)); +} + +// ---------------------------------------------------------------------- + +void CellProperty::callRenderHookFunctions(RenderHookFunctionList *const &renderHookFunctionList) const +{ + if (renderHookFunctionList) + { + const RenderHookFunctionList::const_iterator iEnd = renderHookFunctionList->end(); + for (RenderHookFunctionList::const_iterator i = renderHookFunctionList->begin(); i != iEnd; ++i) + (*i)(); + } +} + +// ---------------------------------------------------------------------- + +void CellProperty::addPreVisibilityTraversalRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + addHookFunction(m_preVisibilityTraversalRenderHookFunctionList, renderHookFunction); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removePreVisibilityTraversalRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + removeHookFunction(m_preVisibilityTraversalRenderHookFunctionList, renderHookFunction); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::callPreVisibilityTraversalRenderHookFunctions() const +{ + callRenderHookFunctions(m_preVisibilityTraversalRenderHookFunctionList); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::addEnterRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + addHookFunction(m_enterRenderHookFunctionList, renderHookFunction); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removeEnterRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + removeHookFunction(m_enterRenderHookFunctionList, renderHookFunction); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::callEnterRenderHookFunctions() const +{ + callRenderHookFunctions(m_enterRenderHookFunctionList); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::addPreDrawRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + addHookFunction(m_preDrawRenderHookFunctionList, renderHookFunction); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removePreDrawRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + removeHookFunction(m_preDrawRenderHookFunctionList, renderHookFunction); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::callPreDrawRenderHookFunctions() const +{ + callRenderHookFunctions(m_preDrawRenderHookFunctionList); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::addExitRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + addHookFunction(m_exitRenderHookFunctionList, renderHookFunction); +} + +// ---------------------------------------------------------------------- + +void CellProperty::removeExitRenderHookFunction(RenderHookFunction renderHookFunction) const +{ + removeHookFunction(m_exitRenderHookFunctionList, renderHookFunction); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::callExitRenderHookFunctions() const +{ + callRenderHookFunctions(m_exitRenderHookFunctionList); +} //lint !e1763 // Member function marked const indirectly modifies class // intentional + +// ---------------------------------------------------------------------- + +void CellProperty::drawDebugShapes(DebugShapeRenderer * const renderer) const +{ + UNREF(renderer); + +#ifdef _DEBUG + + if (renderer == NULL) + return; + + Floor const * const floor = getFloor(); + + if (floor) + floor->drawDebugShapes(renderer,false); + + if (ms_renderPortals) + { + for (uint i = 0; i < m_portalObjectList->size(); ++i) + { + PortalObjectEntry const & entry = (*m_portalObjectList)[i]; + + for (uint j = 0; j < entry.portalList->size(); ++j) + { + Portal const * portal = NON_NULL((*entry.portalList)[j]); + IndexedTriangleList const & portalGeometry = portal->getGeometry(); + + renderer->setDepthTest(false); + renderer->setColor(portal->isClosed() ? VectorArgb::solidYellow : VectorArgb::solidWhite); + renderer->drawMesh(&portalGeometry); + renderer->setDepthTest(true); + } + } + } + + PortalPropertyTemplateCell const & cellTemplate = m_portalProperty->getPortalPropertyTemplate().getCell(m_cellIndex); + + BaseExtent const * collisionExtent = cellTemplate.getCollisionExtent(); + + if(ConfigSharedCollision::getDrawExtents() && collisionExtent) + { + collisionExtent->drawDebugShapes(renderer); + } + + UNREF(cellTemplate); + +#endif +} + +// ---------------------------------------------------------------------- + +Portal *CellProperty::getPortal(int portalIndex) +{ + Portal * result = 0; + if(m_portalObjectList) + { + if(m_portalObjectList->front().portalList) + { + result = m_portalObjectList->front().portalList->operator[](static_cast(portalIndex)); + } + } + return result; +} + +// ---------------------------------------------------------------------- + +int CellProperty::getNumberOfPortalObjects() const +{ + return static_cast(m_portalObjectList->size()); +} + +// ---------------------------------------------------------------------- + +CellProperty::PortalObjectEntry const &CellProperty::getPortalObject(int index) const +{ + return (*m_portalObjectList)[static_cast(index)]; +} + +// ---------------------------------------------------------------------- +/** + * Return true if no access allowed hook function is set; otherwise, return + * the value returned by the AccessAllowedHookFunction. + * + * @return true if no access allowed hook function is set; otherwise, return + * the value returned by the AccessAllowedHookFunction. + */ + +bool CellProperty::getAccessAllowed() const +{ + if (ms_accessAllowedHookFunction != NULL) + return (*ms_accessAllowedHookFunction)(*this); + else + return true; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setEnvironmentTexture(Texture const * environmentTexture) +{ + NOT_NULL(ms_textureFetch); + NOT_NULL(ms_textureRelease); + + if (environmentTexture) + ms_textureFetch(environmentTexture); + + if (m_environmentTexture) + ms_textureRelease(m_environmentTexture); + + m_environmentTexture = environmentTexture; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::isFogEnabled() const +{ + return m_fogEnabled; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setFogEnabled(bool fogEnabled) +{ + m_fogEnabled = fogEnabled; +} + +// ---------------------------------------------------------------------- + +const PackedArgb &CellProperty::getFogColor() const +{ + return m_fogColor; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setFogColor(const PackedArgb &fogColor) +{ + m_fogColor = fogColor; +} + +// ---------------------------------------------------------------------- + +float CellProperty::getFogDensity() const +{ + return m_fogDensity; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setFogDensity(float fogDensity) +{ + m_fogDensity = fogDensity; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::getAppliedInteriorLayout() const +{ + return m_appliedInteriorLayout; +} + +// ---------------------------------------------------------------------- + +void CellProperty::setAppliedInteriorLayout() const +{ + m_appliedInteriorLayout = true; +} + +// ---------------------------------------------------------------------- + +bool CellProperty::isContentItemExposedWith(Object const &item) const +{ + // Cell contents are always exposed to the world with the cell. + UNREF(item); + return true; +} + +// ---------------------------------------------------------------------- + +Vector const CellProperty::getPosition_w(Location const & location) +{ + Vector result = location.getCoordinates(); + CellProperty const * const worldCellProperty = CellProperty::getWorldCellProperty(); + + if (worldCellProperty != NULL) + { + if (location.getCell() != worldCellProperty->getOwner().getNetworkId()) + { + // This is not the world cell, rotate the cell position into + // world space + + Object const * const cell = NetworkIdManager::getObjectById(location.getCell()); + + if (cell != NULL) + { + result = cell->rotateTranslate_o2w(location.getCoordinates()); + } + } + } + + return result; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/portal/CellProperty.h b/engine/shared/library/sharedObject/src/shared/portal/CellProperty.h new file mode 100644 index 00000000..cf3366e6 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/CellProperty.h @@ -0,0 +1,295 @@ +// ====================================================================== +// +// CellProperty.h +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CellProperty_H +#define INCLUDED_CellProperty_H + +// ====================================================================== + +class Appearance; +class BaseClass; +class BaseExtent; +class DebugShapeRenderer; +class Floor; +class Iff; +class IndexedTriangleList; +class Location; +class Object; +class Portal; +class PortalProperty; +class PortalPropertyTemplateCell; +class Texture; +class Vector; +class VectorArgb; + +namespace DPVS +{ + class Cell; +}; + +#include "sharedMath/PackedArgb.h" +#include "sharedObject/Container.h" + +// ====================================================================== + +class CellProperty : public Container +{ + friend class RenderWorld; + friend class PortalProperty; + friend class DpvsHelper; + +public: + + typedef stdvector::fwd VertexList; + typedef stdvector::fwd PortalList; + + typedef void (*AddToRenderWorldHookFunction) (Object& object); + typedef Appearance *(*PolyAppearanceFactory)(VertexList const & verts, VectorArgb const & color); + typedef void (*RenderHookFunction)(); + typedef DPVS::Cell *(*CreateDpvsCellHookFunction)(CellProperty *owner); + typedef void (*DestroyDpvsCellHookFunction)(DPVS::Cell *cellToDestroy); + typedef void (*TextureFetch)(Texture const *texture); + typedef void (*TextureRelease)(Texture const *texture); + typedef void (*DeleteVisibleCellProperty)(CellProperty const *cell); + + typedef bool (*AccessAllowedHookFunction)(CellProperty const &property); + + struct PortalObjectEntry + { + const PortalProperty *portalProperty; + PortalList *portalList; + bool attached; + }; + +public: + + static void install(); + static void setCreateAndDestroyDpvsCellHookFunctions(CreateDpvsCellHookFunction createDpvsCellHookFunction, DestroyDpvsCellHookFunction destroyDpvsCellHookFunction); + static void setPortalTransitionsEnabled(bool enabled); + static void setTextureHookFunctions(TextureFetch textureFetch, TextureRelease textureRelease); + static void setDeleteVisibleCellProperty(DeleteVisibleCellProperty); + + static PropertyId getClassPropertyId(); + static CellProperty *getWorldCellProperty(); + + static void addPortalCrossingNotification(Object &object); + static void removePortalCrossingNotification(Object &object); + + static void setAddToRenderWorldHook(AddToRenderWorldHookFunction hook); + static void setPortalBarrierFactory(PolyAppearanceFactory factory); + static void setForceFieldFactory(PolyAppearanceFactory factory); + static void setAccessAllowedHookFunction(AccessAllowedHookFunction hook); + + static void addToRenderWorld(Object & object); + static Appearance * createPortalBarrier(VertexList const & verts, const VectorArgb &color); + static Appearance * createForceField(VertexList const & verts, const VectorArgb &color); + + static bool areAdjacent(const CellProperty *cellProperty1, const CellProperty *cellProperty2); + + static float getMaximumValidCellSpaceCoordinate(); + + static void releaseWorldCellPropertyEnvironmentTexture(); + + static Vector const getPosition_w(Location const & location); + +public: + + CellProperty(Object &cellObject); + ~CellProperty(); + + bool isWorldCell() const; + virtual bool isContentItemExposedWith(Object const &item) const; + + virtual int depersistContents(const Object& item); + virtual bool internalItemRemoved(const Object& item); + + virtual bool mayAdd(const Object &item, ContainerErrorCode& error) const; + virtual bool remove(Object &item, ContainerErrorCode& error); + virtual bool remove(ContainerIterator &pos, ContainerErrorCode& error); + virtual int getTypeId() const; + virtual void debugPrint(std::string &buffer) const; + + virtual void removeFromWorld(); + + const PortalProperty *getPortalProperty() const; + const char *getCellName() const; + const uint32 getCellNameCrc() const; + int getCellIndex() const; + int getPortalCount() const; + + Object *getAppearanceObject(); + const Object *getAppearanceObject() const; + + CellProperty *getDestinationCell(const Vector &startPosition, const Vector &endPosition, float &t, bool passableOnly=false) const; + CellProperty *getDestinationCell(const Object *object, int portalId) const; + bool getDestinationCells(const Sphere &sphere, stdvector::fwd & outCells) const; + + bool isAdjacentTo(const CellProperty *cell) const; + void addObject_w(Object &object); + + Floor *getFloor(); + const Floor *getFloor() const; + + const BaseExtent *getCollisionExtent() const; + + const BaseClass *getPathGraph() const; + + void addPreVisibilityTraversalRenderHookFunction(RenderHookFunction renderHookFunction) const; + void removePreVisibilityTraversalRenderHookFunction(RenderHookFunction renderHookFunction) const; + void callPreVisibilityTraversalRenderHookFunctions() const; + + void addEnterRenderHookFunction(RenderHookFunction renderHookFunction) const; + void removeEnterRenderHookFunction(RenderHookFunction renderHookFunction) const; + void callEnterRenderHookFunctions() const; + + void addPreDrawRenderHookFunction(RenderHookFunction renderHookFunction) const; + void removePreDrawRenderHookFunction(RenderHookFunction renderHookFunction) const; + void callPreDrawRenderHookFunctions() const; + + void addExitRenderHookFunction(RenderHookFunction renderHookFunction) const; + void removeExitRenderHookFunction(RenderHookFunction renderHookFunction) const; + void callExitRenderHookFunctions() const; + + void drawDebugShapes(DebugShapeRenderer * renderer) const; + + int getNumberOfPortalObjects() const; + PortalObjectEntry const &getPortalObject(int index) const; + + bool getAccessAllowed() const; + + DPVS::Cell *getDpvsCell() const; + + void setEnvironmentTexture(Texture const *texture); + Texture const * getEnvironmentTexture() const; + + void setVisible(bool visible) const; + bool wasVisible() const; + + bool isFogEnabled() const; + void setFogEnabled(bool fogEnabled); + const PackedArgb &getFogColor() const; + void setFogColor(const PackedArgb &fogColor); + float getFogDensity() const; + void setFogDensity(float fogDensity); + + bool getAppliedInteriorLayout() const; + void setAppliedInteriorLayout() const; + +private: + + typedef stdvector::fwd PortalObjectList; + typedef stdvector::fwd RenderHookFunctionList; + +private: + + CellProperty(); + CellProperty(const CellProperty &); + CellProperty &operator =(const CellProperty &); + + void initialize(const PortalProperty &portalProperty, int cellIndex, bool createAppearance); + void attach(const PortalProperty &portalProperty, PortalList *portalList); + void detach(const PortalProperty &portalProperty); + Portal *getPortal(int portalIndex); + + void addHookFunction(RenderHookFunctionList *&renderHookFunctionList, RenderHookFunction renderHookFunction) const; + void removeHookFunction(RenderHookFunctionList *const &renderHookFunctionList, RenderHookFunction renderHookFunction) const; + void callRenderHookFunctions(RenderHookFunctionList *const &renderHookFunctionList) const; + +private: + + static void remove(); + +private: + + static CellProperty *ms_worldCellProperty; + static TextureFetch ms_textureFetch; + static TextureRelease ms_textureRelease; + static DeleteVisibleCellProperty ms_deleteVisibleCellProperty; + +private: + + const PortalProperty *m_portalProperty; + int m_cellIndex; + mutable Object *m_appearanceObject; + PortalObjectList *m_portalObjectList; + mutable bool m_visible; + Floor *m_floor; + const char *m_cellName; + uint32 m_cellNameCrc; + DPVS::Cell *m_dpvsCell; + const Texture *m_environmentTexture; + bool m_fogEnabled; + PackedArgb m_fogColor; + float m_fogDensity; + bool mutable m_appliedInteriorLayout; + + mutable RenderHookFunctionList *m_preVisibilityTraversalRenderHookFunctionList; + mutable RenderHookFunctionList *m_enterRenderHookFunctionList; + mutable RenderHookFunctionList *m_preDrawRenderHookFunctionList; + mutable RenderHookFunctionList *m_exitRenderHookFunctionList; +}; + +// ====================================================================== + +inline const char *CellProperty::getCellName() const +{ + return m_cellName; +} + +// ---------------------------------------------------------------------- + +inline const uint32 CellProperty::getCellNameCrc() const +{ + return m_cellNameCrc; +} + +// ---------------------------------------------------------------------- + +inline DPVS::Cell *CellProperty::getDpvsCell() const +{ + return m_dpvsCell; +} + +// ---------------------------------------------------------------------- + +inline const PortalProperty *CellProperty::getPortalProperty() const +{ + return m_portalProperty; +} + +// ---------------------------------------------------------------------- + +inline int CellProperty::getCellIndex() const +{ + return m_cellIndex; +} + +// ---------------------------------------------------------------------- + +inline Texture const * CellProperty::getEnvironmentTexture() const +{ + return m_environmentTexture; +} + +// ---------------------------------------------------------------------- + +inline void CellProperty::setVisible(bool visible) const +{ + m_visible = visible; +} + +// ---------------------------------------------------------------------- + +inline bool CellProperty::wasVisible() const +{ + return m_visible; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/Portal.cpp b/engine/shared/library/sharedObject/src/shared/portal/Portal.cpp new file mode 100644 index 00000000..c9d7219c --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/Portal.cpp @@ -0,0 +1,429 @@ +// ====================================================================== +// +// Portal.cpp +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Portal.h" + +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/Containment3d.h" +#include "sharedCollision/DoorInfo.h" +#include "sharedCollision/DoorObject.h" +#include "sharedCollision/Overlap3d.h" +#include "sharedFile/Iff.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/IndexedTriangleList.h" +#include "sharedMath/Plane3d.h" +#include "sharedMath/Sphere.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/PortalPropertyTemplate.h" +#include "sharedUtility/DataTable.h" + +#include + +// ====================================================================== + +namespace PortalNamespace +{ + DataTable *ms_doorStyleTable; + + Portal::ClosedStateChangedHookFunction ms_closedStateChangedHookFunction; + Portal::CreateDpvsPortalHookFunction ms_createDpvsPortalHookFunction; + Portal::DestroyDpvsPortalHookFunction ms_destroyDpvsPortalHookFunction; + bool ms_createDoors = false; +} +using namespace PortalNamespace; + +// ====================================================================== + +void Portal::install() +{ + Iff dataTableIff; + + if (dataTableIff.open("datatables/appearance/door_style.iff", true)) + { + delete ms_doorStyleTable; + ms_doorStyleTable = new DataTable(); + NOT_NULL(ms_doorStyleTable); + ms_doorStyleTable->load(dataTableIff); + } + + ExitChain::add(&Portal::remove,"Portal::remove"); +} + +// ---------------------------------------------------------------------- + +void Portal::remove() +{ + delete ms_doorStyleTable; + ms_doorStyleTable = NULL; +} + +// ---------------------------------------------------------------------- + +void Portal::setHookFunctions(CreateDpvsPortalHookFunction createDpvsPortalHookFunction, DestroyDpvsPortalHookFunction destroyDpvsPortalHookFunction, ClosedStateChangedHookFunction closedStateChangedHookFunction, bool createDoors) +{ + ms_closedStateChangedHookFunction = closedStateChangedHookFunction; + ms_createDpvsPortalHookFunction = createDpvsPortalHookFunction; + ms_destroyDpvsPortalHookFunction = destroyDpvsPortalHookFunction; + ms_createDoors = createDoors; +} + +// ---------------------------------------------------------------------- + +void Portal::preloadDoorStyle(const char* const doorStyle, std::vector& preloadAppearanceTemplateList) +{ + int row = ms_doorStyleTable->searchColumnString (0, doorStyle); + if (row == -1) + return; + + uint i; + for (i = 1; i < 4; ++i) + { + const std::string& appearanceTemplateName = ms_doorStyleTable->getStringValue (i,row); + if (!appearanceTemplateName.empty ()) + { + const AppearanceTemplate* const appearanceTemplate = AppearanceTemplateList::fetch (appearanceTemplateName.c_str ()); + appearanceTemplate->preloadAssets (); + preloadAppearanceTemplateList.push_back (appearanceTemplate); + } + } +} + +// ====================================================================== + +Portal::Portal(const PortalPropertyTemplateCellPortal &portalTemplate, CellProperty *parentCell, Object *relativeTo) +: + m_template(portalTemplate), + m_relativeToObject(relativeTo), + m_closed(false), + m_neighbor(NULL), + m_parentCell(parentCell), + m_dpvsPortal(NULL), + m_door(NULL), + m_appearance(NULL) +{ + if(ms_createDoors) + { + createDoor(); + } +} + +// ---------------------------------------------------------------------- + +Portal::~Portal() +{ + if (m_dpvsPortal) + { + m_relativeToObject->removeDpvsObject(m_dpvsPortal); + NOT_NULL(ms_destroyDpvsPortalHookFunction); + (*ms_destroyDpvsPortalHookFunction)(m_dpvsPortal); + m_dpvsPortal = NULL; + } + + m_relativeToObject = NULL; + m_neighbor = NULL; + m_parentCell = NULL; + m_door = NULL; + delete m_appearance; +} + +// ---------------------------------------------------------------------- + +const Transform Portal::getDoorTransform() const +{ + return m_template.getDoorTransform(); +} + +// ---------------------------------------------------------------------- + +const AxialBox Portal::getLocalBox() const +{ + const Transform t = getDoorTransform(); + + AxialBox tempBox; + VertexList const &geometry = getGeometry().getVertices(); + VertexList::const_iterator iEnd = geometry.end(); + for (VertexList::const_iterator i = geometry.begin(); i != iEnd; ++i) + tempBox.add(t.rotateTranslate_p2l(*i)); + + return tempBox; +} + +// ---------------------------------------------------------------------- + +void Portal::getLocalVerts(VertexList &vertices) const +{ + const Transform t = getDoorTransform(); + + VertexList const &geometry = getGeometry().getVertices(); + + vertices.clear(); + vertices.reserve(geometry.size()); + + VertexList::const_iterator iEnd = geometry.end(); + for (VertexList::const_iterator i = geometry.begin(); i != iEnd; ++i) + vertices.push_back(t.rotateTranslate_p2l(*i)); +} + +// ---------------------------------------------------------------------- + +IndexedTriangleList const & Portal::getGeometry() const +{ + NOT_NULL(m_template.m_portalGeometry); + return *m_template.m_portalGeometry; +} + +// ---------------------------------------------------------------------- + +bool Portal::isGeometryWindingOrderClockwise() const +{ + return m_template.m_geometryWindingClockwise; +} + +// ---------------------------------------------------------------------- + +bool Portal::testPenetration(const Vector &begin, const Vector &end, float &t) const +{ + if (isDisabled()) + return false; + + //-- For clockwise ordering, we test from start to end. For counterclockwise ordering, we test end to start + Vector result; + if ((isGeometryWindingOrderClockwise() && getGeometry().collide(begin, end, result)) || (!isGeometryWindingOrderClockwise() && getGeometry().collide(end, begin, result))) + { + const float lineLength = begin.magnitudeBetween(end); + t = lineLength > 0.f ? begin.magnitudeBetween(result) / lineLength : 0.f; + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool Portal::testOverlap(const Sphere &sphere) const +{ + if (isDisabled()) + return false; + + IndexedTriangleList const & indexedTriangleList = getGeometry(); + std::vector const & vertices = indexedTriangleList.getVertices(); + std::vector const & indices = indexedTriangleList.getIndices(); + uint const numberOfFaces = indices.size() / 3; + + VertexList vertexList; + for (uint faceIndex = 0, index = 0; faceIndex < numberOfFaces; ++faceIndex) + { + Vector const & v0 = vertices[indices[index++]]; + Vector const & v1 = vertices[indices[index++]]; + Vector const & v2 = vertices[indices[index++]]; + + vertexList.clear(); + vertexList.push_back(v0); + vertexList.push_back(v1); + vertexList.push_back(v2); + + Plane3d const plane(v0, v1, v2); + + if (Overlap3d::TestSpherePoly(sphere, vertexList, plane)) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +void Portal::createDoor () +{ + DoorInfo info; + const char *doorStyle = m_template.m_doorStyle; + if (!doorStyle || !doorStyle[0]) + { + info.m_frameAppearance = 0; + info.m_doorAppearance = 0; + info.m_doorAppearance2 = 0; + info.m_doorFlip2 = 0; + info.m_delta = Vector::zero; + info.m_openTime = 0.f; + info.m_closeTime = 0.f; + info.m_spring = 0.f; + info.m_smoothness = 0.f; + info.m_triggerRadius = 0.f; + info.m_forceField = false; + info.m_openBeginEffect = 0; + info.m_openEndEffect = 0; + info.m_closeBeginEffect = 0; + info.m_closeEndEffect = 0; + info.m_portalGeometry = m_template.m_portalGeometry; + info.m_alwaysOpen = true; + } + else + { + //@todo - Look up door info from a datatable instead of hardcoding it + int row = ms_doorStyleTable->searchColumnString(0,doorStyle); + if(row == -1) + { + DEBUG_WARNING(true,("Portal::createDoor - Can't find door style entry for style %s - using placeholder\n", doorStyle)); + row = 0; + } + + info.m_frameAppearance = ms_doorStyleTable->getStringValue( 1,row); + info.m_doorAppearance = ms_doorStyleTable->getStringValue( 2,row); + info.m_doorAppearance2 = ms_doorStyleTable->getStringValue( 3,row); + info.m_doorFlip2 = ms_doorStyleTable->getIntValue ( 4,row) ? true : false; + info.m_delta.x = ms_doorStyleTable->getFloatValue ( 5,row); + info.m_delta.y = ms_doorStyleTable->getFloatValue ( 6,row); + info.m_delta.z = ms_doorStyleTable->getFloatValue ( 7,row); + info.m_openTime = ms_doorStyleTable->getFloatValue ( 8,row); + info.m_closeTime = ms_doorStyleTable->getFloatValue ( 9,row); + info.m_spring = ms_doorStyleTable->getFloatValue (10,row); + info.m_smoothness = ms_doorStyleTable->getFloatValue (11,row); + info.m_triggerRadius = ms_doorStyleTable->getFloatValue (12,row); + info.m_forceField = ms_doorStyleTable->getIntValue (13,row) ? true : false; + info.m_openBeginEffect = ms_doorStyleTable->getStringValue(14,row); + info.m_openEndEffect = ms_doorStyleTable->getStringValue(15,row); + info.m_closeBeginEffect = ms_doorStyleTable->getStringValue(16,row); + info.m_closeEndEffect = ms_doorStyleTable->getStringValue(17,row); + info.m_portalGeometry = m_template.m_portalGeometry; + info.m_alwaysOpen = false; + } + + m_door = new DoorObject(info, this); + m_door->setTransform_o2p(getDoorTransform()); + + if(m_door->getBarrier()) + m_door->getBarrier()->setTransform_o2p(getDoorTransform()); + + CellProperty::addToRenderWorld(*m_door); + for (int i = 0; i < m_door->getNumberOfDrawnDoors(); ++i) + CellProperty::addToRenderWorld(*m_door->getDrawnDoor(i)); + if (m_door->getBarrier()) + CellProperty::addToRenderWorld(*m_door->getBarrier()); + + m_door->attachToObject_p(m_relativeToObject, true); + + if(m_door->getBarrier()) + m_door->getBarrier()->attachToObject_p(m_relativeToObject,true); +} + +// ---------------------------------------------------------------------- + +bool Portal::isDisabled() const +{ +#ifdef _DEBUG + if (ConfigSharedObject::getAllowDisabledPortals()) + return false; +#endif + + return m_template.m_disabled; +} + +// ---------------------------------------------------------------------- +// Determine if players are allowed to pass through this portal or not. + +bool Portal::isPassable() const +{ + if (m_template.m_passable) + { + CellProperty const * const cell = getParentCell(); + + if (cell != 0) + { + return cell->getAccessAllowed(); + } + + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool Portal::isPassageAllowed() const +{ + if (isPassable() && !isDisabled()) + { + Portal const * neighbor = getNeighbor(); + + CellProperty const * neighborCell = (neighbor != 0) ? neighbor->getParentCell() : 0; + + if (neighborCell != 0) + { + return neighborCell->getAccessAllowed(); + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +void Portal::setClosed(bool closed) +{ + if (m_closed != closed) //lint !e731 // (Info -- Boolean argument to equal/not equal) // This is the intended logic. + { + m_closed = closed; + if (ms_closedStateChangedHookFunction) + (*ms_closedStateChangedHookFunction)(*this); + } +} + +// ---------------------------------------------------------------------- + +void Portal::setNeighbor(Portal *neighbor) +{ + m_neighbor = neighbor; + if (m_door) + m_door->setNeighbor(m_neighbor->m_door); + + if (!m_dpvsPortal && ms_createDpvsPortalHookFunction) + { + m_dpvsPortal = (*ms_createDpvsPortalHookFunction)(this); + m_relativeToObject->addDpvsObject(m_dpvsPortal); + } +} + +// ---------------------------------------------------------------------- + +void Portal::removeFromDpvs() +{ + if (m_dpvsPortal != 0) + { + m_relativeToObject->removeDpvsObject(m_dpvsPortal); + NOT_NULL(ms_destroyDpvsPortalHookFunction); + (*ms_destroyDpvsPortalHookFunction)(m_dpvsPortal); + m_dpvsPortal = 0; + } + + delete m_appearance; + m_appearance = 0; +} + +// ---------------------------------------------------------------------- + +void Portal::setAppearance(Appearance *appearance) +{ + delete m_appearance; + m_appearance = appearance; +} + +// ---------------------------------------------------------------------- + +Object * Portal::getDoorObject() +{ + return m_door; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/portal/Portal.h b/engine/shared/library/sharedObject/src/shared/portal/Portal.h new file mode 100644 index 00000000..d34f3cd0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/Portal.h @@ -0,0 +1,149 @@ +// ====================================================================== +// +// Portal.h +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Portal_H +#define INCLUDED_Portal_H + +// ====================================================================== + +class Appearance; +class AppearanceTemplate; +class AxialBox; +class Cell; +class CellProperty; +class DoorInfo; +class DoorObject; +class Iff; +class IndexedTriangleList; +class PortalPropertyTemplateCellPortal; +class Vector; + +namespace DPVS +{ + class Object; +} + +#include "sharedObject/PortalProperty.h" + +// ====================================================================== + +class Portal +{ + friend class Cell; + friend class PortalProperty; + +public: + + typedef stdvector::fwd VertexList; + typedef DPVS::Object *(*CreateDpvsPortalHookFunction)(Portal *owner); + typedef void (*DestroyDpvsPortalHookFunction)(DPVS::Object *cellToDestroy); + typedef void (*ClosedStateChangedHookFunction)(Portal &); + + static void install(); + static void remove(); + static void setHookFunctions(CreateDpvsPortalHookFunction createDpvsPortalHookFunction, DestroyDpvsPortalHookFunction destroyDpvsPortalHookFunction, ClosedStateChangedHookFunction closedStateChangedHookFunction, bool createDoors); + static void preloadDoorStyle(const char *doorStyle, stdvector::fwd& preloadAppearanceTemplateList); + +public: + + Portal(const PortalPropertyTemplateCellPortal &portalTemplate, CellProperty *parentCell, Object *relativeTo); + ~Portal(); + + IndexedTriangleList const & getGeometry() const; + bool isGeometryWindingOrderClockwise() const; + bool testPenetration(const Vector &begin, const Vector &end, float &t) const; + bool testOverlap(const Sphere &sphere) const; + + // These two methods are slightly different - If a portal represents a door, + // then isPassable returns true. If the server has told the client that the client + // isn't allowed to enter the cell on the other side of the portal, then isPassageAllowed + // returns false + + bool isDisabled() const; + bool isPassable() const; + bool isPassageAllowed() const; + + bool isClosed() const; + void setClosed(bool closed); + + Portal *getNeighbor(); + const Portal *getNeighbor() const; + + Transform const getDoorTransform() const; + + CellProperty *getParentCell() const; + + // Get local (door-relative) versions of the portal's bounding box and vertex list + AxialBox const getLocalBox() const; + void getLocalVerts(VertexList &vertices) const; + + DPVS::Object *getDpvsObject(); + void removeFromDpvs(); + + void setAppearance(Appearance *appearance); + Object * getDoorObject(); + +private: + + Portal(); + Portal(const Portal &); + Portal &operator =(const Portal &); + + void setNeighbor(Portal *neighbor); + void createDoor(); + +private: + + PortalPropertyTemplateCellPortal const &m_template; + Object *m_relativeToObject; + bool m_closed; + Portal *m_neighbor; + CellProperty *m_parentCell; + DPVS::Object *m_dpvsPortal; + DoorObject *m_door; + Appearance *m_appearance; +}; + +// ====================================================================== + +inline bool Portal::isClosed() const +{ + return m_closed; +} + +// ---------------------------------------------------------------------- + +inline Portal * Portal::getNeighbor() +{ + return m_neighbor; +} + +// ---------------------------------------------------------------------- + +inline Portal const * Portal::getNeighbor() const +{ + return m_neighbor; +} + +// ---------------------------------------------------------------------- + +inline CellProperty *Portal::getParentCell() const +{ + return m_parentCell; +} + +// ---------------------------------------------------------------------- + +inline DPVS::Object *Portal::getDpvsObject() +{ + return m_dpvsPortal; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.cpp b/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.cpp new file mode 100644 index 00000000..6605cebf --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.cpp @@ -0,0 +1,716 @@ +// ====================================================================== +// +// PortalProperty.cpp +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/PortalProperty.h" + +#include "sharedCollision/DoorObject.h" +#include "sharedCollision/Floor.h" +#include "sharedCollision/FloorManager.h" +#include "sharedCollision/FloorLocator.h" +#include "sharedDebug/DataLint.h" +#include "sharedFile/Iff.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Portal.h" +#include "sharedObject/PortalPropertyTemplate.h" +#include "sharedObject/PortalPropertyTemplateList.h" + +#include + +// ====================================================================== + +const Tag TAG_PRTP = TAG(P,R,T,P); + +// ====================================================================== + +PortalProperty::BeginCreateObjectFunction PortalProperty::ms_beginCreateObjectFunction; +PortalProperty::EndCreateObjectFunction PortalProperty::ms_endCreateObjectFunction; + +// ====================================================================== + +void PortalProperty::install(BeginCreateObjectFunction beginCreateObjectFunction, EndCreateObjectFunction endCreateObjectFunction) +{ + ms_beginCreateObjectFunction = beginCreateObjectFunction; + ms_endCreateObjectFunction = endCreateObjectFunction; + Portal::install(); +} + +// ---------------------------------------------------------------------- + +PropertyId PortalProperty::getClassPropertyId() +{ + return PROPERTY_HASH(PortalObjectProperty, 0x939616B9); +} + +// ====================================================================== + +PortalProperty::PortalProperty(Object &owner, const char *fileName) +: Container(getClassPropertyId(), owner), + m_template(NULL), + m_cellList(new CellList), + m_fixupList(NULL), + m_hasPassablePortalToParentCell(false) +{ +#ifdef _DEBUG + DataLint::pushAsset(fileName); +#endif // _DEBUG + + m_template = PortalPropertyTemplateList::fetch(CrcLowerString(fileName)); + m_cellList->resize(static_cast(m_template->getNumberOfCells()), NULL); + +#ifdef _DEBUG + DataLint::popAsset(); +#endif // _DEBUG +} + +// ---------------------------------------------------------------------- + +PortalProperty::~PortalProperty() +{ + delete m_cellList; + delete m_fixupList; + if (m_template) + { + m_template->release(); + m_template = 0; + } + + m_fixupList = 0; +} + +// ---------------------------------------------------------------------- + +void PortalProperty::initializeFirstTimeObject() +{ + // the first cell is the parent cell, so don't actually create an object/cell pair for it + int numberOfCells = m_template->getNumberOfCells(); + for (int i = 1; i < numberOfCells; ++i) + { + ContainerErrorCode tmp = CEC_Success; + Object *object = ms_beginCreateObjectFunction(i); + IGNORE_RETURN(addToContents(*object, tmp)); + cellLoaded(i, *object, false); + if (ms_endCreateObjectFunction) + ms_endCreateObjectFunction(object); + } //lint !e429 // Custodial pointer not freed or returned +} + +// ---------------------------------------------------------------------- + +void PortalProperty::clientSinglePlayerInitializeFirstTimeObject() +{ + // the first cell is the parent cell, so don't actually create an object/cell pair for it + int numberOfCells = m_template->getNumberOfCells(); + for (int i = 1; i < numberOfCells; ++i) + { + ContainerErrorCode tmp = CEC_Success; + Object *object = ms_beginCreateObjectFunction(i); + IGNORE_RETURN(addToContents(*object, tmp)); + if (ms_endCreateObjectFunction) + ms_endCreateObjectFunction(object); + } //lint !e429 // Custodial pointer not freed or returned +} + +// ---------------------------------------------------------------------- + +const PortalPropertyTemplate &PortalProperty::getPortalPropertyTemplate() const +{ + NOT_NULL(m_template); + return *m_template; +} + +// ---------------------------------------------------------------------- + +void PortalProperty::addToWorld() +{ +#ifdef _DEBUG + { + int unloaded = 0; + int const numberOfCells = static_cast(m_cellList->size()); + for (int i = 1; i < numberOfCells; ++i) + if ((*m_cellList)[static_cast(i)] == NULL) + { + WARNING(true, ("cell %d/%d not loaded", i, numberOfCells)); + ++unloaded; + } + DEBUG_FATAL(unloaded , ("%d/%d cells not loaded", unloaded, numberOfCells-1)); + } +#endif + + + CellProperty *parentCell = getOwner().getParentCell(); + + // create the portals that lead into this portal property + PortalList *portalList = m_template->createExteriorPortalList(parentCell, &getOwner()); + + // now that all the portals have been created, let every portal know who its neighbor is + PortalPropertyTemplate::PortalOwnersList const &portalOwnersList = m_template->getPortalOwnersList(); + PortalPropertyTemplate::PortalOwnersList::const_iterator const iEnd = portalOwnersList.end(); + for (PortalPropertyTemplate::PortalOwnersList::const_iterator i = portalOwnersList.begin(); i != iEnd; ++i) + { + CellProperty *cell[2]; + Portal *portal[2]; + + for (int j = 0; j < 2; ++j) + { + const int cellIndex = i->owners[j].cell; + const int portalIndex = i->owners[j].portal; + + if (cellIndex == 0) + { + cell[j] = parentCell; + portal[j] = (*portalList)[static_cast(portalIndex)]; + if (portal[j]->isPassable()) + m_hasPassablePortalToParentCell = true; + } + else + { + cell[j] = (*m_cellList)[static_cast(cellIndex)]; + portal[j] = cell[j]->getPortal(portalIndex); + } + } + + portal[0]->setNeighbor(portal[1]); + portal[1]->setNeighbor(portal[0]); + } + + parentCell->attach(*this, portalList); + Container::addToWorld(); +} + +// ---------------------------------------------------------------------- + +void PortalProperty::removeFromWorld() +{ + Container::removeFromWorld(); + CellProperty *parentCell = getOwner().getParentCell(); + parentCell->detach(*this); +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::serverEndBaselines(int serverObjectCrc, std::vector &unfixables, bool authoritative) +{ + bool retval = false; + ContainerErrorCode tmp = CEC_Success; + + // check if the CRC has changed cells + const int crc = m_template->getCrc(); + if (authoritative && (crc == 0 || serverObjectCrc != crc)) + { + retval = true; + + // create any missing cells + uint const numberOfCells = m_cellList->size(); + for (uint i = 1; i < numberOfCells; ++i) + { + if ((*m_cellList)[i] == NULL) + { + Object *object = ms_beginCreateObjectFunction(static_cast(i)); + IGNORE_RETURN(addToContents(*object, tmp)); + cellLoaded(static_cast(i), *object, false); + if (ms_endCreateObjectFunction) + ms_endCreateObjectFunction(object); + } //lint !e429 // Custodial pointer not freed or returned + } + + //-- jww: this fixup code is broken + //-- fixupObject() causes the fixedup object to get added to the world before its parent has been + //-- for now, we won't queue anything for fixup + +#if 0 + // go through the cells and remove objects + for (size_t cell=1 ; cell< numberOfCells; ++cell) + { + for (ContainerIterator cellContents=(*m_cellList)[cell]->begin(); cellContents != (*m_cellList)[cell]->end(); ++cellContents) + { + Object *obj = (*cellContents).getObject(); + if (obj) + { + queueObjectForFixup(*obj); + IGNORE_RETURN((*m_cellList)[cell]->remove(cellContents, tmp)); // does not invalidate the iterator + } + } + } + +#endif + + } +#ifdef _DEBUG + else + { + if (ConfigSharedObject::getValidateCellContentsAttached()) + { + // make sure the contents of every cell is attached to the cell + uint const numberOfCells = m_cellList->size(); + for (size_t cellIndex = 1 ; cellIndex < numberOfCells; ++cellIndex) + { + CellProperty *cell = (*m_cellList)[cellIndex]; + DEBUG_WARNING(! cell, ("Expected to get a cell, none was returned")); + if(cell) + { + Object const * const cellObject = &cell->getOwner(); + for (ContainerIterator cellContents=cell->begin(); cellContents != cell->end(); ++cellContents) + { + Object *obj = (*cellContents).getObject(); + DEBUG_FATAL(obj && obj->getAttachedTo() != cellObject, ("Cell content not attached to cell")); + if (obj && obj->getAttachedTo() != cellObject) + { + WARNING(true, ("CellProblem Cell content not attached to cell")); + } + } + } + } + } + } +#endif + + // For each object, find the appropriate cell and place the object in it + // Note that objects can be put in m_fixupList from other places, not just the above code) + if (m_fixupList) + { + for (FixupList::iterator fixRec=(*m_fixupList).begin(); fixRec!=(*m_fixupList).end(); ++fixRec) + { + // put object into appropriate cell + if (!fixupObject(*((*fixRec).m_obj), (*fixRec).m_transform)) + unfixables.push_back((*fixRec).m_obj); + } + + delete m_fixupList; + m_fixupList = 0; + } + return retval; +} + +// ---------------------------------------------------------------------- + +/** + * Given an object, attempt to put it in the POB in the best cell. + * This function is used when the POB has changed or for player logins. + * @param object The object to place. + * @param intendedTransform Where the object should be placed, relative to the POB. + * May adjust the postion in the transform to make sure + * the object is on a floor, but will preserve the rotation. + * @return true on success, false if the object cannot be placed. + * @see PortalProperty::serverEndBaselines + */ +bool PortalProperty::fixupObject (Object &object, Transform intendedTransform) +{ + Object *cell; + Vector newPosition; + if (findContainingCell(intendedTransform.getPosition_p(),newPosition,cell)) + { + CellProperty *cellProperty = cell->getCellProperty(); + if (cellProperty) + { + //FIX HERE. Set the transform before calling add object_w which adds it to the world. + cellProperty->addObject_w(object); + intendedTransform.setPosition_p(newPosition); + object.setTransform_o2p(intendedTransform); + if (!object.isInWorld()) + object.addToWorld(); + + object.pobFixupComplete(); + return true; + } + else + { + WARNING_STRICT_FATAL(true,("findContainingCell returned object %s, which that lacks a cellProperty.\n",cell->getNetworkId().getValueString().c_str())); + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +/** + * @param buildingPos - Position inside the building we're trying to find a cell for + * + * @param outPos - Position on a floor in the building that's close to the test position + * @param outCell - Cell object in the building the test position is in + * + * @return - True if we found a position, false if not. + */ +bool PortalProperty::findContainingCell(Vector const &buildingPos, Vector &outPos, Object *&outCell) +{ + Object &buildingObject = getOwner(); + + // ---------- + // Object is a portallized object. + // Search through its cells to find the floor closest to the test point + + int minChild = -1; + Vector minPos = Vector::zero; + float minDist = REAL_MAX; + + for(int i = 0; i < buildingObject.getNumberOfChildObjects(); i++) + { + // ---------- + // Skip all child objects that aren't cells or that don't have a floor + + Object const * const childObject = buildingObject.getChildObject(i); + if (!childObject) + continue; + + CellProperty const * const cellProperty = childObject->getCellProperty(); + if (!cellProperty) + continue; + + Floor const * const floor = cellProperty->getFloor(); + if (!floor) + continue; + + // ---------- + // Found a cell with a floor + + FloorLocator loc; + + if(floor->findClosestLocation(buildingPos,loc)) + { + Vector floorPos = loc.getPosition_p(); + + float dist = (floorPos - buildingPos).magnitude(); + + if(dist < minDist) + { + minChild = i; + minPos = floorPos; + minDist = dist; + } + } + } + + if(minChild != -1) + { + outPos.x = minPos.x; + outPos.z = minPos.z; + outPos.y = std::max(minPos.y,buildingPos.y); + + outCell = buildingObject.getChildObject(minChild); + + return true; + } + else + { + return false; + } +} + + +// ---------------------------------------------------------------------- + +bool PortalProperty::mayAdd(const Object &, ContainerErrorCode& error) const +{ + error = CEC_Success; + return true; +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::remove(Object &item, ContainerErrorCode& error) +{ + return Container::remove(item, error); +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::remove(ContainerIterator &pos, ContainerErrorCode& error) +{ + return Container::remove(pos, error); +} + +// ---------------------------------------------------------------------- + +int PortalProperty::getTypeId() const +{ + return static_cast(TAG_PRTP); +} + +// ---------------------------------------------------------------------- + +void PortalProperty::debugPrint(std::string &buffer) const +{ + char tempBuffer[1024]; + + buffer += "====[BEGIN: portal property]====\n"; + + sprintf(tempBuffer, "container id [%s].\n", getOwner().getNetworkId().getValueString().c_str()); + buffer += tempBuffer; + + buffer += "embedding container contents now:\n"; + Container::debugPrint(buffer); + + buffer += "====[END: portal property]====\n"; +} + +// ---------------------------------------------------------------------- + +void PortalProperty::createAppearance() +{ + Appearance * const appearance = AppearanceTemplateList::createAppearance(m_template->getExteriorAppearanceName()); + appearance->setShadowBlobAllowed(); + getOwner().setAppearance(appearance); +} + +// ---------------------------------------------------------------------- + +char const *PortalProperty::getExteriorFloorName() const +{ + return m_template->getExteriorFloorName(); +} + +// ---------------------------------------------------------------------- + +void PortalProperty::cellLoaded(int cellIndex, Object &cellObject, bool shouldCreateAppearance) +{ + DEBUG_FATAL(cellIndex < 1 || cellIndex >= static_cast(m_cellList->size()), ("invalid cell index %d/%d", cellIndex, static_cast(m_cellList->size()))); + DEBUG_FATAL((*m_cellList)[static_cast(cellIndex)], ("cell already loaded")); + if ((*m_cellList)[static_cast(cellIndex)]) + { + WARNING(true, ("CellProblem for portal %s cell index %d already loaded", getOwner().getNetworkId().getValueString().c_str(), cellIndex)); + } + + // attach the cell as a child of the portal object + cellObject.attachToObject_p(&getOwner(), false); + + // get the cell property from the cell object + CellProperty *cell = cellObject.getCellProperty(); + + // store that + (*m_cellList)[static_cast(cellIndex)] = cell; + + // let the cell know who its portal object is, and what its portal data is + cell->initialize(*this, cellIndex, shouldCreateAppearance); +} + +// ---------------------------------------------------------------------- + +int PortalProperty::getNumberOfCells() const +{ + return m_template->getNumberOfCells(); +} + +// ---------------------------------------------------------------------- + +CellProperty *PortalProperty::getCell(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCells()); + return (*m_cellList)[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +const CellProperty *PortalProperty::getCell(int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCells()); + return (*m_cellList)[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +#if 0 + +int PortalProperty::getNumberOfLights(int cellIndex) const +{ + DEBUG_FATAL(cellIndex < 0 || cellIndex >= static_cast(m_cellList->size()), ("cell index out of range")); + return (*m_cellDataList)[cellIndex]->getNumberOfLights(); +} + +// ---------------------------------------------------------------------- + +const PortalProperty::LightData &PortalProperty::getLightData(int cellIndex, int lightIndex) const +{ + DEBUG_FATAL(cellIndex < 0 || cellIndex >= static_cast(m_cellList->size()), ("cell index out of range")); + return (*m_cellDataList)[cellIndex]->getLightData(lightIndex); +} + +#endif + +// ---------------------------------------------------------------------- + +const PortalProperty::CellNameList &PortalProperty::getCellNames() const +{ + return m_template->getCellNames(); +} + +// ---------------------------------------------------------------------- + +CellProperty *PortalProperty::getCell(const char *desiredCellName) +{ + const int numberOfCells = getNumberOfCells(); + for (int i = 1; i < numberOfCells; ++i) + { + PortalPropertyTemplateCell const &cell = m_template->getCell(i); + char const * const cellName = cell.getName(); + + if (cellName && strcmp(desiredCellName, cellName) == 0) + return (*m_cellList)[static_cast(i)]; + } + + return NULL; +} + +// ---------------------------------------------------------------------- + +const CellProperty *PortalProperty::getCell(const char *cellName) const +{ + return const_cast(this)->getCell(cellName); +} + +// ---------------------------------------------------------------------- + +const char *PortalProperty::getCellAppearanceName(int index) const +{ + return m_template->getCell(index).getAppearanceName(); +} + +// ---------------------------------------------------------------------- + +/** + * Queue an object to be placed in the appropriate cell after EndBaseslines. + * Use this function during database load when you find an object that cannot + * be placed in a cell (due to deleted cells, etc.). After the POB receives + * EndBaselines, it will go through every object queued by this function and + * find an appropriate cell for it. + * + * If the object is already in an (incorrect) cell, do not remove the object + * from the cell before calling this function, because removing the object + * will change its transform. This function saves the transform, so you may + * remove the object after calling this function. + */ + +void PortalProperty::queueObjectForFixup(Object &object) +{ + FixupRec temp; + temp.m_obj = &object; + temp.m_transform = object.getTransform_o2p(); // removing the object changes its transform, so we save it now + + if (!m_fixupList) + m_fixupList = new FixupList; + m_fixupList->push_back(temp); +} + +// ---------------------------------------------------------------------- + +int PortalProperty::getCrc() const +{ + return m_template->getCrc(); +} + +// ---------------------------------------------------------------------- + +const char *PortalProperty::getPobName() const +{ + return m_template->getCrcString().getString(); +} + +// ---------------------------------------------------------------------- + +const char *PortalProperty::getPobShortName() const +{ + return m_template->getShortName().getString(); +} + +// ---------------------------------------------------------------------- + +Transform const PortalProperty::getEjectionLocationTransform() const +{ + return m_template->getEjectionLocationTransform(); +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::isContentItemObservedWith(Object const &item) const +{ + // Immediate contents of portallized objects are always observed with them. + UNREF(item); + return true; +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::isContentItemExposedWith(Object const &item) const +{ + // Portallized objects always expose their immediate contents with themselves. + UNREF(item); + return true; +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::canContentsBeObservedWith() const +{ + return true; +} + +// ---------------------------------------------------------------------- + +bool PortalProperty::hasPassablePortalToParentCell() const +{ + return m_hasPassablePortalToParentCell; +} + +// ---------------------------------------------------------------------- +// position_l is in the space of the building. + +CellProperty const * PortalProperty::findContainingCell(Vector const & position_l) const +{ + CellProperty const * cell = CellProperty::getWorldCellProperty(); + + Object const & buildingObject = getOwner(); + + float minDist = std::numeric_limits::max(); + + for (int i = 0; i < buildingObject.getNumberOfChildObjects(); i++) + { + Object const * const childObject = buildingObject.getChildObject(i); + if (!childObject) + continue; + + CellProperty const * const cellProperty = childObject->getCellProperty(); + if (!cellProperty) + continue; + + Floor const * const floor = cellProperty->getFloor(); + if (!floor) + continue; + + FloorLocator loc; + + if (floor->findClosestLocation(position_l, loc)) + { + float const distance = (position_l - loc.getPosition_p()).magnitudeSquared(); + + if(distance < minDist) + { + minDist = distance; + + PortalProperty const * const portal = childObject->getPortalProperty(); + if (portal) + { + CellProperty const * const childCellProperty = portal->findContainingCell(loc.getPosition_p()); + cell = childCellProperty && (childCellProperty != CellProperty::getWorldCellProperty()) ? childCellProperty : cellProperty; + } + else + { + cell = cellProperty; + } + } + } + } + + return cell; +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.h b/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.h new file mode 100644 index 00000000..8701d28f --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalProperty.h @@ -0,0 +1,133 @@ +// ====================================================================== +// +// PortalProperty.h +// Copyright 2001 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PortalProperty_H +#define INCLUDED_PortalProperty_H + +// ====================================================================== + +class CellProperty; +class Floor; +class Iff; +class Object; +class Portal; +class PortalPropertyTemplate; +class Vector; + +#include "sharedObject/Container.h" +#include "sharedMath/Transform.h" + +// ====================================================================== + +class PortalProperty : public Container +{ + class Notification; + + friend class CellProperty; + friend class RenderWorld; + friend class Notification; + +public: + + static PropertyId getClassPropertyId(); + +public: + + typedef stdvector::fwd PortalList; + typedef stdvector::fwd CellNameList; + typedef stdvector::fwd VertexList; + + typedef Object *(*BeginCreateObjectFunction)(int cellIndex); + typedef void (*EndCreateObjectFunction)(Object *newObject); + +public: + + static void install(BeginCreateObjectFunction beginCreateObjectFunction, EndCreateObjectFunction endCreateObjectFunction); + +public: + + PortalProperty(Object &owner, const char *portalPropertyFileName); + virtual ~PortalProperty(); + + virtual void initializeFirstTimeObject(); + void clientSinglePlayerInitializeFirstTimeObject(); + + virtual void addToWorld(); + virtual void removeFromWorld(); + + virtual bool isContentItemObservedWith(Object const &item) const; + virtual bool isContentItemExposedWith(Object const &item) const; + virtual bool canContentsBeObservedWith() const; + + virtual bool mayAdd(const Object &item, ContainerErrorCode& error) const; + virtual bool remove(Object &item, ContainerErrorCode& error); + virtual bool remove(ContainerIterator &pos, ContainerErrorCode& error); + virtual int getTypeId() const; + virtual void debugPrint(std::string &buffer) const; + + bool serverEndBaselines(int crc,stdvector::fwd &unfixables, bool authoritative); + + const PortalPropertyTemplate &getPortalPropertyTemplate() const; + int getCrc() const; + const char *getPobName() const; + const char *getPobShortName() const; + int getNumberOfCells() const; + CellProperty *getCell(int index); + const CellProperty *getCell(int index) const; + const char *getCellAppearanceName(int index) const; + + const CellNameList &getCellNames() const; + CellProperty *getCell(const char *cellName); + const CellProperty *getCell(const char *cellName) const; + + Transform const getEjectionLocationTransform() const; + + char const *getExteriorFloorName() const; + + void createAppearance(); + void cellLoaded(int cellIndex, Object &cellObject, bool shouldCreateAppearance); + + bool findContainingCell(Vector const & buildingPos, Vector & outPos, Object * & outCell); + void queueObjectForFixup(Object &object); + bool fixupObject(Object &object, Transform intendedTransform); + bool hasPassablePortalToParentCell() const; + CellProperty const * findContainingCell(Vector const & position_l) const; + +private: + + PortalProperty(); + PortalProperty(const PortalProperty &); + PortalProperty &operator =(const PortalProperty &); + +private: + + struct FixupRec + { + Object *m_obj; + Transform m_transform; + }; + typedef stdvector::fwd FixupList; + typedef stdvector::fwd CellList; + +private: + + static BeginCreateObjectFunction ms_beginCreateObjectFunction; + static EndCreateObjectFunction ms_endCreateObjectFunction; + static Notification ms_notification; + +private: + + const PortalPropertyTemplate *m_template; + CellList *m_cellList; + FixupList *m_fixupList; + bool m_hasPassablePortalToParentCell; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.cpp b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.cpp new file mode 100644 index 00000000..5fda59b0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.cpp @@ -0,0 +1,1774 @@ +// ====================================================================== +// +// PortalPropertyTemplate.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/PortalPropertyTemplate.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/DataResourceList.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/IndexedTriangleList.h" +#include "sharedMath/Plane.h" +#include "sharedCollision/BaseClass.h" +#include "sharedCollision/ConfigSharedCollision.h" +#include "sharedCollision/Extent.h" +#include "sharedCollision/ExtentList.h" +#include "sharedCollision/FloorMesh.h" +#include "sharedCollision/FloorManager.h" // for the path graph factory +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/Object.h" +#include "sharedObject/Portal.h" +#include "sharedObject/PortalPropertyTemplateList.h" +#include "sharedPathfinding/SimplePathGraph.h" +#include "sharedPathfinding/DynamicPathGraph.h" +#include "sharedPathfinding/DynamicPathNode.h" +#include "sharedPathfinding/PathEdge.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "sharedUtility/FileName.h" + +#include +#include +#include +#include + +typedef BaseClass * (*ExpandBuildingGraphHook)( PortalPropertyTemplate * portalTemplate, BaseClass * baseBuildingGraph ); + +ExpandBuildingGraphHook g_expandBuildingGraphHook = NULL; + +// ====================================================================== + +const Tag TAG_CRC = TAG3(C,R,C); + +const Tag TAG_CELL = TAG(C,E,L,L); +const Tag TAG_CELS = TAG(C,E,L,S); +const Tag TAG_LGHT = TAG(L,G,H,T); +const Tag TAG_PRTL = TAG(P,R,T,L); +const Tag TAG_PRTO = TAG(P,R,T,O); +const Tag TAG_PRTS = TAG(P,R,T,S); +const Tag TAG_PGRF = TAG(P,G,R,F); + +// ====================================================================== + +namespace PortalPropertyTemplateNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + typedef std::map NameTransformMap; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void remove(); + + int getRequiredColumnNumberFromNamedTable(char const *filename, DataTable const *table, char const *columnName); + void loadEjectionPointData(char const *filename); + + IndexedTriangleList * createPortalGeometry(PortalPropertyTemplate::VertexList const & VertexList); + void scalePortalVertices(IndexedTriangleList & indexedTriangleList); + +#ifdef _DEBUG + void validateCoplanar(IndexedTriangleList const & indexedTriangleList, char const * const fileName); +#endif + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + bool s_installed; + NameTransformMap s_ejectionTransformMap; +} + +using namespace PortalPropertyTemplateNamespace; + +// ====================================================================== +// namespace PortalPropertyTemplateNamespace +// ====================================================================== + +void PortalPropertyTemplateNamespace::remove() +{ + FATAL(!s_installed, ("PortalPropertyTemplateNamespace not installed.")); + s_installed = false; + + s_ejectionTransformMap.clear(); +} + +// ---------------------------------------------------------------------- + +int PortalPropertyTemplateNamespace::getRequiredColumnNumberFromNamedTable(char const *filename, DataTable const *table, char const *columnName) +{ + NOT_NULL(columnName); + + int const columnNumber = table->findColumnNumber(columnName); + FATAL(columnNumber < 0, ("failed to find column name [%s] in PortalPropertyTemplate ejection transform file [%s].", columnName, filename)); + + return columnNumber; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateNamespace::loadEjectionPointData(char const *filename) +{ + NOT_NULL(filename); + + //-- Load the data table. + DataTable *const table = DataTableManager::getTable(filename, true); + FATAL(!table, ("PortalPropertyTemplate ejection point data file [%s] failed to open.", filename)); + + //-- Find required data column numbers. + int const pobFileNameColumnNumber = getRequiredColumnNumberFromNamedTable(filename, table, "pob_file_name"); + int const ejectXColumnNumber = getRequiredColumnNumberFromNamedTable(filename, table, "eject_x"); + int const ejectYColumnNumber = getRequiredColumnNumberFromNamedTable(filename, table, "eject_y"); + int const ejectZColumnNumber = getRequiredColumnNumberFromNamedTable(filename, table, "eject_z"); + int const ejectFacingYawColumnNumber = getRequiredColumnNumberFromNamedTable(filename, table, "eject_facing_yaw_degrees"); + + //-- Loop through data, constructing entries as necessary. + int const rowCount = table->getNumRows(); + for (int rowIndex = 0; rowIndex < rowCount; ++rowIndex) + { + //-- Get pob file name. + std::string const &pobFileName = table->getStringValue(pobFileNameColumnNumber, rowIndex); + FATAL(pobFileName.empty(), ("File [%s], row [%d]: POB filename is zero-length.", filename, rowIndex + 1)); + + //-- Construct the transform for the ejection point. Ejection point transforms are in the + // same parent space as the building. + float const ejectX = table->getFloatValue(ejectXColumnNumber, rowIndex); + float const ejectY = table->getFloatValue(ejectYColumnNumber, rowIndex); + float const ejectZ = table->getFloatValue(ejectZColumnNumber, rowIndex); + float const yawDegrees = table->getFloatValue(ejectFacingYawColumnNumber, rowIndex); + + Transform ejectionTransform; + ejectionTransform.yaw_l(yawDegrees * PI_OVER_180); + ejectionTransform.setPosition_p(Vector(ejectX, ejectY, ejectZ)); + + //-- Add to map. + std::pair const result = s_ejectionTransformMap.insert(NameTransformMap::value_type(PersistentCrcString(pobFileName.c_str(), true), ejectionTransform)); + FATAL(!result.second, ("Failed to insert pob filename [%s] into ejection point map, probably a duplicate name in datatable filename [%s].", pobFileName.c_str(), filename)); + } + + DataTableManager::close(filename); + +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void PortalPropertyTemplateNamespace::validateCoplanar(IndexedTriangleList const & indexedTriangleList, char const * const fileName) +{ + std::vector const & vertexList = indexedTriangleList.getVertices(); + uint const numberOfVertices = vertexList.size(); + DEBUG_FATAL(numberOfVertices < 3, ("Portal with fewer than 3 vertices")); + Plane p(vertexList[0], vertexList[1], vertexList[2]); + for (uint i = 3; i < numberOfVertices; ++i) + { + float const distance = p.computeDistanceTo(vertexList[i]); + WARNING(abs(distance) > 0.001f, ("[%s]: portal is not planar, vertex %d is %8.6f from the plane", fileName, static_cast(i), distance)); + } +} +#endif + +// ---------------------------------------------------------------------- + +IndexedTriangleList * PortalPropertyTemplateNamespace::createPortalGeometry(PortalPropertyTemplate::VertexList const & vertices) +{ + IndexedTriangleList * const indexedTriangleList = new IndexedTriangleList; + indexedTriangleList->addTriangleFan(&vertices[0], static_cast(vertices.size())); + return indexedTriangleList; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateNamespace::scalePortalVertices(IndexedTriangleList & indexedTriangleList) +{ + std::vector & vertexList = indexedTriangleList.getVertices(); + + const uint numberOfVertices = vertexList.size(); + const float portalScale = ConfigSharedObject::getPortalScale(); + if (numberOfVertices > 0 && portalScale > 1.f) + { + uint j; + + // compute the center + Vector center; + for (j = 0; j < numberOfVertices; ++j) + center += vertexList[j]; + + center /= static_cast(numberOfVertices); + + // scale portal vertices + for (j = 0; j < numberOfVertices; ++j) + { + vertexList[j] -= center; + vertexList[j] *= portalScale; + vertexList[j] += center; + } + } +} + +// ====================================================================== + +class PortalPropertyTemplateCellPortal::PreloadManager +{ +public: + + explicit PreloadManager (const PortalPropertyTemplateCellPortal* portalPropertyTemplateCellPortal); + ~PreloadManager (); + +private: + + PreloadManager (); + PreloadManager (const PreloadManager&); + PreloadManager& operator= (const PreloadManager&); + +private: + + typedef std::vector PreloadAppearanceTemplateList; + PreloadAppearanceTemplateList m_preloadAppearanceTemplateList; +}; + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCellPortal::PreloadManager::PreloadManager (const PortalPropertyTemplateCellPortal* const portalPropertyTemplateCellPortal) : + m_preloadAppearanceTemplateList () +{ + if (portalPropertyTemplateCellPortal->m_doorStyle && portalPropertyTemplateCellPortal->m_doorStyle [0]) + Portal::preloadDoorStyle (portalPropertyTemplateCellPortal->m_doorStyle, m_preloadAppearanceTemplateList); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCellPortal::PreloadManager::~PreloadManager () +{ + uint i; + for (i = 0; i < m_preloadAppearanceTemplateList.size (); ++i) + AppearanceTemplateList::release (m_preloadAppearanceTemplateList [i]); + + m_preloadAppearanceTemplateList.clear (); +} + +// ====================================================================== + +PortalPropertyTemplateCellPortal::PortalPropertyTemplateCellPortal(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +: + m_disabled(false), + m_passable(false), + m_geometryWindingClockwise(true), + m_portalGeometry(NULL), + m_doorStyle(NULL), + m_hasDoorHardpoint(false), + m_doorHardpoint(), + m_plane(), + m_preloadManager (0) +{ + load(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + computePlaneEquation(); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCellPortal::~PortalPropertyTemplateCellPortal() +{ + m_portalGeometry = NULL; + delete [] m_doorStyle; + + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + iff.enterForm(TAG_PRTL); + + switch (iff.getCurrentName()) + { + case TAG_0001: + load_0001(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + break; + + case TAG_0002: + load_0002(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + break; + + case TAG_0003: + load_0003(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + break; + + case TAG_0004: + load_0004(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + break; + + case TAG_0005: + load_0005(portalPropertyTemplate, cellIndex, cellPortalIndex, iff); + break; + + default: + { + char buffer[256]; + iff.formatLocation(buffer, sizeof(buffer)); + DEBUG_FATAL(true, ("Unknown portal version at %s", buffer)); + } + } + + iff.exitForm(TAG_PRTL); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load_0001(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + // read the portal data and reverse flag + iff.enterChunk(TAG_0001); + + m_disabled = false; + m_passable = true; + int const geometryIndex = iff.read_int32(); + m_geometryWindingClockwise = iff.read_bool8(); + m_portalGeometry = portalPropertyTemplate.getPortalGeometry(geometryIndex, cellIndex, cellPortalIndex, m_geometryWindingClockwise); + IGNORE_RETURN(iff.read_int32()); // target cell index + + iff.exitChunk(TAG_0001); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load_0002(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + iff.enterChunk(TAG_0002); + + m_disabled = false; + m_passable = iff.read_bool8(); + int const geometryIndex = iff.read_int32(); + m_geometryWindingClockwise = iff.read_bool8(); + m_portalGeometry = portalPropertyTemplate.getPortalGeometry(geometryIndex, cellIndex, cellPortalIndex, m_geometryWindingClockwise); + IGNORE_RETURN(iff.read_int32()); // target cell index + + iff.exitChunk(TAG_0002); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load_0003(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + iff.enterChunk(TAG_0003); + + m_disabled = false; + m_passable = iff.read_bool8(); + int const geometryIndex = iff.read_int32(); + m_geometryWindingClockwise = iff.read_bool8(); + m_portalGeometry = portalPropertyTemplate.getPortalGeometry(geometryIndex, cellIndex, cellPortalIndex, m_geometryWindingClockwise); + IGNORE_RETURN(iff.read_int32()); // target cell index + m_doorStyle = iff.read_string(); + + iff.exitChunk(TAG_0003); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load_0004(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + iff.enterChunk(TAG_0004); + + m_passable = iff.read_bool8(); + int const geometryIndex = iff.read_int32(); + m_geometryWindingClockwise = iff.read_bool8(); + m_portalGeometry = portalPropertyTemplate.getPortalGeometry(geometryIndex, cellIndex, cellPortalIndex, m_geometryWindingClockwise); + IGNORE_RETURN(iff.read_int32()); // target cell index + m_doorStyle = iff.read_string(); + m_hasDoorHardpoint = iff.read_bool8(); + m_doorHardpoint = iff.read_floatTransform(); + + iff.exitChunk(TAG_0004); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::load_0005(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff) +{ + iff.enterChunk(TAG_0005); + + m_disabled = iff.read_bool8(); + m_passable = iff.read_bool8(); + int const geometryIndex = iff.read_int32(); + m_geometryWindingClockwise = iff.read_bool8(); + m_portalGeometry = portalPropertyTemplate.getPortalGeometry(geometryIndex, cellIndex, cellPortalIndex, m_geometryWindingClockwise); + IGNORE_RETURN(iff.read_int32()); // target cell index + m_doorStyle = iff.read_string(); + m_hasDoorHardpoint = iff.read_bool8(); + m_doorHardpoint = iff.read_floatTransform(); + + iff.exitChunk(TAG_0005); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::computePlaneEquation() +{ + NOT_NULL(m_portalGeometry); + std::vector const & vertices = m_portalGeometry->getVertices(); + std::vector const & indices = m_portalGeometry->getIndices(); + Vector const & v0 = vertices[indices[0]]; + Vector const & v1 = vertices[m_geometryWindingClockwise ? indices[1] : indices[2]]; + Vector const & v2 = vertices[m_geometryWindingClockwise ? indices[2] : indices[1]]; + m_plane.set(v0, v1, v2); +} + +// ---------------------------------------------------------------------- + +Transform const PortalPropertyTemplateCellPortal::getDoorTransform(bool useDoorHardpoint) const +{ + if (useDoorHardpoint && m_hasDoorHardpoint) + return m_doorHardpoint; + + // If there's no door hardpoint, the door orientation is aligned with the portal's plane + Transform doorTransform; + Vector portalNormal = m_plane.getNormal(); + Vector up(0.0f,1.0f,0.0f); + Vector right = up.cross(portalNormal); + doorTransform.setLocalFrameIJK_p(right, up, portalNormal); + + // The door position is the center of the bottom of the portal's bounding box + if (m_portalGeometry) + { + std::vector const & vertices = m_portalGeometry->getVertices(); + + AxialBox tempBox; + std::vector::const_iterator iEnd = vertices.end(); + for (std::vector::const_iterator i = vertices.begin(); i != iEnd; ++i) + tempBox.add(*i); + + doorTransform.setPosition_p(tempBox.getBase()); + } + + return doorTransform; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::flipPassable() +{ + m_passable = !m_passable; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::preloadAssets() const +{ + if (!m_preloadManager) + m_preloadManager = new PreloadManager (this); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCellPortal::garbageCollect() const +{ + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } +} + +// ====================================================================== + +class PortalPropertyTemplateCell::PreloadManager +{ +public: + + explicit PreloadManager (const PortalPropertyTemplateCell* portalPropertyTemplateCell); + ~PreloadManager (); + +private: + + PreloadManager (); + PreloadManager (const PreloadManager&); + PreloadManager& operator= (const PreloadManager&); + +private: + + const AppearanceTemplate* m_preloadAppearanceTemplate; +}; + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCell::PreloadManager::PreloadManager (const PortalPropertyTemplateCell* const portalPropertyTemplateCell) : + m_preloadAppearanceTemplate (0) +{ + if (portalPropertyTemplateCell->m_appearanceName) + { + m_preloadAppearanceTemplate = AppearanceTemplateList::fetch (portalPropertyTemplateCell->m_appearanceName); + m_preloadAppearanceTemplate->preloadAssets (); + } + + + IGNORE_RETURN( portalPropertyTemplateCell->getFloorMesh() ); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCell::PreloadManager::~PreloadManager () +{ + if (m_preloadAppearanceTemplate) + AppearanceTemplateList::release (m_preloadAppearanceTemplate); +} + +// ====================================================================== + +PortalPropertyTemplateCell::PortalPropertyTemplateCell(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +: + m_name(NULL), + m_appearanceName(NULL), + m_floorName(NULL), + m_floorMesh(NULL), + m_canSeeParentCell(false), + m_lightList(NULL), + m_portalList(new PortalPropertyTemplateCellPortalList), + m_collisionExtent(NULL), + m_preloadManager (0) +{ + load(portalPropertyTemplate, index, iff); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCell::~PortalPropertyTemplateCell() +{ + delete [] m_name; + delete [] m_appearanceName; + delete [] m_floorName; + delete m_lightList; + + { + while (!m_portalList->empty()) + { + delete m_portalList->back(); + m_portalList->pop_back(); + } + delete m_portalList; + } + + delete m_collisionExtent; + m_collisionExtent = NULL; + + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } + + if (m_floorMesh) + { + m_floorMesh->releaseReference (); + m_floorMesh = NULL; + } +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::load(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_CELL); + + switch (iff.getCurrentName()) + { + case TAG_0001: + load_0001(portalPropertyTemplate, index, iff); + break; + + case TAG_0002: + load_0002(portalPropertyTemplate, index, iff); + break; + + case TAG_0003: + load_0003(portalPropertyTemplate, index, iff); + break; + + case TAG_0004: + load_0004(portalPropertyTemplate, index, iff); + break; + + case TAG_0005: + load_0005(portalPropertyTemplate, index, iff); + break; + + default: + { + char buffer[256]; + iff.formatLocation(buffer, sizeof(buffer)); + DEBUG_FATAL(true, ("Unknown portal object version at %s", buffer)); + } + } + + iff.exitForm(TAG_CELL); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::load_0001(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_0001); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + m_canSeeParentCell = iff.read_bool8(); + m_appearanceName = iff.read_string(); + iff.exitChunk(TAG_DATA); + + m_portalList->reserve(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + m_portalList->push_back(new PortalPropertyTemplateCellPortal(portalPropertyTemplate, index, i, iff)); + + iff.exitForm(TAG_0001); + + char buffer[16]; + sprintf(buffer, "old_%d", index); + m_name = DuplicateString(buffer); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::load_0002(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_0002); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + m_canSeeParentCell = iff.read_bool8(); + m_appearanceName = iff.read_string(); + bool hasFloor = iff.read_bool8(); + if(hasFloor) + { + m_floorName = iff.read_string(); + } + iff.exitChunk(TAG_DATA); + + m_portalList->reserve(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + m_portalList->push_back(new PortalPropertyTemplateCellPortal(portalPropertyTemplate, index, i, iff)); + + iff.exitForm(TAG_0002); + + char buffer[16]; + sprintf(buffer, "old_%d", index); + m_name = DuplicateString(buffer); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::load_0003(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_0003); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + m_canSeeParentCell = iff.read_bool8(); + m_appearanceName = iff.read_string(); + bool hasFloor = iff.read_bool8(); + if(hasFloor) + { + m_floorName = iff.read_string(); + } + iff.exitChunk(TAG_DATA); + + m_portalList->reserve(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + m_portalList->push_back(new PortalPropertyTemplateCellPortal(portalPropertyTemplate, index, i, iff)); + + iff.enterChunk(TAG_LGHT); + const int numberOfLights = iff.read_int32(); + + if (numberOfLights) + { + m_lightList = new LightList; + m_lightList->reserve(static_cast(numberOfLights)); + + for (int j = 0; j < numberOfLights; ++j) + { + Light light; + + light.type = static_cast(iff.read_int8()); + light.diffuseColor = iff.read_floatVectorArgb(); + light.specularColor = iff.read_floatVectorArgb(); + light.transform = iff.read_floatTransform(); + light.constantAttenuation = iff.read_float(); + light.linearAttenuation = iff.read_float(); + light.quadraticAttenuation = iff.read_float(); + + // hack to deal with bad data coming out of maya exporter + light.transform.yaw_l(PI); + + m_lightList->push_back(light); + } + } + iff.exitChunk(TAG_LGHT); + + iff.exitForm(TAG_0003); + + char buffer[16]; + sprintf(buffer, "old_%d", index); + m_name = DuplicateString(buffer); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::load_0004(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_0004); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + m_canSeeParentCell = iff.read_bool8(); + m_name = iff.read_string(); + m_appearanceName = iff.read_string(); + bool hasFloor = iff.read_bool8(); + + if(hasFloor) + m_floorName = iff.read_string(); + + iff.exitChunk(TAG_DATA); + + m_portalList->reserve(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + m_portalList->push_back(new PortalPropertyTemplateCellPortal(portalPropertyTemplate, index, i, iff)); + + iff.enterChunk(TAG_LGHT); + const int numberOfLights = iff.read_int32(); + + if (numberOfLights) + { + IS_NULL(m_lightList); + m_lightList = new LightList; + m_lightList->reserve(static_cast(numberOfLights)); + + for (int j = 0; j < numberOfLights; ++j) + { + Light light; + + light.type = static_cast(iff.read_int8()); + light.diffuseColor = iff.read_floatVectorArgb(); + light.specularColor = iff.read_floatVectorArgb(); + light.transform = iff.read_floatTransform(); + light.constantAttenuation = iff.read_float(); + light.linearAttenuation = iff.read_float(); + light.quadraticAttenuation = iff.read_float(); + + // hack to deal with bad data coming out of maya exporter + light.transform.yaw_l(PI); + + m_lightList->push_back(light); + } + } + iff.exitChunk(TAG_LGHT); + + iff.exitForm(TAG_0004); +} + +// ---------------------------------------------------------------------- +//@todo - This is just skipping over the collision extent form for now + +void PortalPropertyTemplateCell::load_0005(const PortalPropertyTemplate &portalPropertyTemplate, int index, Iff &iff) +{ + iff.enterForm(TAG_0005); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + m_canSeeParentCell = iff.read_bool8(); + m_name = iff.read_string(); + m_appearanceName = iff.read_string(); + bool hasFloor = iff.read_bool8(); + + if(hasFloor) + m_floorName = iff.read_string(); + + iff.exitChunk(TAG_DATA); + + m_collisionExtent = ExtentList::create(iff); + + m_portalList->reserve(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + m_portalList->push_back(new PortalPropertyTemplateCellPortal(portalPropertyTemplate, index, i, iff)); + + iff.enterChunk(TAG_LGHT); + const int numberOfLights = iff.read_int32(); + + if (numberOfLights) + { + IS_NULL(m_lightList); + m_lightList = new LightList; + m_lightList->reserve(static_cast(numberOfLights)); + + for (int j = 0; j < numberOfLights; ++j) + { + Light light; + + light.type = static_cast(iff.read_int8()); + light.diffuseColor = iff.read_floatVectorArgb(); + light.specularColor = iff.read_floatVectorArgb(); + light.transform = iff.read_floatTransform(); + light.constantAttenuation = iff.read_float(); + light.linearAttenuation = iff.read_float(); + light.quadraticAttenuation = iff.read_float(); + + // hack to deal with bad data coming out of maya exporter + light.transform.yaw_l(PI); + + m_lightList->push_back(light); + } + } + iff.exitChunk(TAG_LGHT); + + iff.exitForm(TAG_0005); +} + +// ---------------------------------------------------------------------- + +const char *PortalPropertyTemplateCell::getName() const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +const char *PortalPropertyTemplateCell::getAppearanceName() const +{ + return m_appearanceName; +} + +// ---------------------------------------------------------------------- + +bool PortalPropertyTemplateCell::canSeeParentCell() const +{ + return m_canSeeParentCell; +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCell::PortalList *PortalPropertyTemplateCell::createPortalList(CellProperty *parentCell, Object *relativeToObject) const +{ + PortalList *portalList = new PortalList; + portalList->reserve(m_portalList->size()); + + // create all the portals for the cell + PortalPropertyTemplateCellPortalList::const_iterator iEnd = m_portalList->end(); + for (PortalPropertyTemplateCellPortalList::const_iterator i = m_portalList->begin(); i != iEnd; ++i) + portalList->push_back(new Portal(**i, parentCell, relativeToObject)); + + return portalList; +} + +// ---------------------------------------------------------------------- + +const char *PortalPropertyTemplateCell::getFloorName() const +{ + return m_floorName; +} + +// ---------------------------------------------------------------------- + +FloorMesh const * PortalPropertyTemplateCell::getFloorMesh() const +{ + if(m_floorMesh == NULL) + { + if(m_floorName) + { + PortalPropertyTemplateCell * cell = const_cast(this); + + cell->m_floorMesh = FloorMeshList::fetch(m_floorName); + } + else + { + //-- cell template r0 always has a null floor name for POBs without accessible exteriors (POB ships & POB-only dungeons) + //-- don't warn for that cell template + DEBUG_WARNING(ConfigSharedCollision::getReportWarnings() && strcmp(m_name, "r0"), + ("PortalPropertyTemplateCell::getFloorMesh() - Cell template %s on [%s] has no floor name", m_name, m_appearanceName)); + } + } + + return m_floorMesh; +} + + +// ---------------------------------------------------------------------- + +PortalPropertyTemplateCell::LightList const *PortalPropertyTemplateCell::getLightList() const +{ + return m_lightList; +} + +// ---------------------------------------------------------------------- + +const BaseExtent *PortalPropertyTemplateCell::getCollisionExtent() const +{ + return m_collisionExtent; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::preloadAssets() const +{ + if (!m_preloadManager) + m_preloadManager = new PreloadManager (this); + + int const numberOfPortals = m_portalList->size(); + for (int i = 0; i < numberOfPortals; ++i) + (*m_portalList)[i]->preloadAssets(); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateCell::garbageCollect() const +{ + if (m_preloadManager) + { + delete m_preloadManager; + m_preloadManager = 0; + } + + int const numberOfPortals = m_portalList->size(); + for (int i = 0; i < numberOfPortals; ++i) + (*m_portalList)[i]->garbageCollect(); +} + +// ====================================================================== + +PortalPropertyTemplate::PortalOwners::Owner::Owner() +: + cell(-1), + portal(-1) +{ +} + +// ====================================================================== + +void PortalPropertyTemplate::install(char const *const pobEjectionTransformFilename) +{ + FATAL(s_installed, ("PortalPropertyTemplate already installed.")); + + //-- Load the pob-specific ejection point information if specified. + // Only the server needs to load this data for SWG at the time of this writing. + if (pobEjectionTransformFilename) + loadEjectionPointData(pobEjectionTransformFilename); + + s_installed = true; + ExitChain::add(PortalPropertyTemplateNamespace::remove, "PortalPropertyTemplate"); +} + +// ---------------------------------------------------------------------- + +bool PortalPropertyTemplate::extractPortalLayoutCrc (const char *fileName, uint32 &portalLayoutCrc) +{ + Iff iff; + if (iff.open(fileName, true)) + { + iff.enterForm(TAG_PRTO); + + switch (iff.getCurrentName()) + { + case TAG_0000: + return false; + + case TAG_0001: + iff.enterForm(TAG_0001); + if (iff.seekChunk(TAG_CRC)) + { + iff.enterChunk(TAG_CRC); + portalLayoutCrc = iff.read_uint32(); + iff.exitChunk(TAG_CRC); + return true; + } + return false; + + case TAG_0002: + iff.enterForm(TAG_0002); + if (iff.seekChunk(TAG_CRC)) + { + iff.enterChunk(TAG_CRC); + portalLayoutCrc = iff.read_uint32(); + iff.exitChunk(TAG_CRC); + return true; + } + return false; + + case TAG_0003: + iff.enterForm(TAG_0003); + if (iff.seekChunk(TAG_CRC)) + { + iff.enterChunk(TAG_CRC); + portalLayoutCrc = iff.read_uint32(); + iff.exitChunk(TAG_CRC); + return true; + } + return false; + + case TAG_0004: + iff.enterForm(TAG_0004); + if (iff.seekChunk(TAG_CRC)) + { + iff.enterChunk(TAG_CRC); + portalLayoutCrc = iff.read_uint32(); + iff.exitChunk(TAG_CRC); + return true; + } + return false; + + default: + return false; + } + } + + return false; +} + +// ====================================================================== + +PortalPropertyTemplate::PortalPropertyTemplate(const CrcString &name) +: + m_referenceCount(0), + m_name(name), + m_shortName(), + m_portalGeometryList(new PortalGeometryList), + m_portalOwnersList(new PortalOwnersList), + m_cellList(new CellList), + m_cellNameList(new CellNameList), + m_crc(0), + m_pathGraph(NULL), + m_radarPortalGeometry(0) +{ + FileName shortName(name.getString()); + shortName.stripPathAndExt(); + m_shortName.set(shortName, true); + + Iff iff(m_name.getString()); + load(iff); + buildRadarPortalGeometry(); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplate::~PortalPropertyTemplate() +{ + PortalPropertyTemplateList::erase(*this); + + { + while (!m_portalGeometryList->empty()) + { + delete m_portalGeometryList->back(); + m_portalGeometryList->pop_back(); + } + delete m_portalGeometryList; + } + + { + while (!m_cellList->empty()) + { + delete m_cellList->back(); + m_cellList->pop_back(); + } + delete m_cellList; + } + + delete m_cellNameList; + delete m_portalOwnersList; + + delete m_pathGraph; + m_pathGraph = NULL; + + delete m_radarPortalGeometry; + m_radarPortalGeometry = 0; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::release() const +{ + if (--m_referenceCount <= 0) + { + DEBUG_FATAL(m_referenceCount < 0, ("reference count went negative")); + delete const_cast(this); + } +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::preloadAssets() const +{ + int const numberOfCells = getNumberOfCells(); + for (int i = 0; i < numberOfCells; ++i) + getCell(i).preloadAssets(); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::garbageCollect() const +{ + int const numberOfCells = getNumberOfCells(); + for (int i = 0; i < numberOfCells; ++i) + getCell(i).garbageCollect(); +} + +// ---------------------------------------------------------------------- + +IndexedTriangleList const * PortalPropertyTemplate::getPortalGeometry(int portalIndex) const +{ + DEBUG_FATAL(portalIndex < 0 || portalIndex >= static_cast(m_portalGeometryList->size()), ("index out of range %d/%d", portalIndex, static_cast(m_portalGeometryList->size()))); + return (*m_portalGeometryList)[static_cast(portalIndex)]; +} + +// ---------------------------------------------------------------------- + +IndexedTriangleList const * PortalPropertyTemplate::getPortalGeometry(int portalIndex, int cell, int cellPortalIndex, bool clockwise) const +{ + DEBUG_FATAL(portalIndex < 0 || portalIndex >= static_cast(m_portalGeometryList->size()), ("index out of range %d/%d", portalIndex, static_cast(m_portalGeometryList->size()))); + PortalOwners::Owner &owner = (*m_portalOwnersList)[static_cast(portalIndex)].owners[clockwise ? 1 : 0]; + owner.cell = cell; + owner.portal = cellPortalIndex; + return (*m_portalGeometryList)[static_cast(portalIndex)]; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load(Iff &iff) +{ + iff.enterForm(TAG_PRTO); + + switch (iff.getCurrentName()) + { + case TAG_0000: + load_0000(iff); + break; + + case TAG_0001: + load_0001(iff); + break; + + case TAG_0002: + load_0002(iff); + break; + + case TAG_0003: + load_0003(iff); + break; + + case TAG_0004: + load_0004(iff); + break; + + // ************************************************************************************************************** + // NOTE! If you add new load functions, you MUST also ensure that PortalPropertyTemplate::extractPortalLayoutCrc() works! + // ************************************************************************************************************** + + default: + { + char buffer[256]; + iff.formatLocation(buffer, sizeof(buffer)); + DEBUG_FATAL(true, ("Unknown portal object version at %s", buffer)); + } + } + + iff.exitForm(TAG_PRTO); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load_0000(Iff &iff) +{ + iff.enterForm(TAG_0000); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + const int numberOfCells = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + // load all the portal geometry + iff.enterForm(TAG_PRTS); + m_portalGeometryList->reserve(static_cast(numberOfPortals)); + m_portalOwnersList->resize(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + { + iff.enterChunk(TAG_PRTL); + + VertexList vertexList; + + const int numberOfVertices = iff.read_int32(); + vertexList.reserve(static_cast(numberOfVertices)); + for (int j = 0; j < numberOfVertices; ++j) + vertexList.push_back(iff.read_floatVector()); + + IndexedTriangleList * const portalGeometry = createPortalGeometry(vertexList); + m_portalGeometryList->push_back(portalGeometry); + +#ifdef _DEBUG + validateCoplanar(*portalGeometry, iff.getFileName()); +#endif + + scalePortalVertices(*portalGeometry); + + iff.exitChunk(TAG_PRTL); + } + iff.exitForm(TAG_PRTS); + + // load all the cells + iff.enterForm(TAG_CELS); + m_cellList->reserve(static_cast(numberOfCells)); + for (int j = 0; j < numberOfCells; ++j) + { + Cell *cell = new Cell(*this, j, iff); + m_cellList->push_back(cell); + + if (j > 0) + { + const char *cellName = cell->getName(); + if (cellName) + m_cellNameList->push_back(cellName); + } + } + iff.exitForm(TAG_CELS); + + DEBUG_WARNING(true, ("PortalProperty::load_0000 - %s does not have a portal property crc and should be re-exported", iff.getFileName ())); + +#ifdef _DEBUG + { + // verify all the portals have two matches + PortalOwnersList::const_iterator const iEnd = m_portalOwnersList->end(); + for (PortalOwnersList::const_iterator k = m_portalOwnersList->begin(); k != iEnd; ++k) + { + PortalOwners const &owners = *k; + DEBUG_FATAL(owners.owners[0].cell < 0 || owners.owners[0].portal < 0, ("Could not find counter-clockwise owner for portal")); + DEBUG_FATAL(owners.owners[1].cell < 0 || owners.owners[1].portal < 0, ("Could not find clockwise owner for portal")); + } + } +#endif + + iff.exitForm(TAG_0000); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load_0001(Iff &iff) +{ + iff.enterForm(TAG_0001); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + const int numberOfCells = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + // load all the portal geometry + iff.enterForm(TAG_PRTS); + m_portalGeometryList->reserve(static_cast(numberOfPortals)); + m_portalOwnersList->resize(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + { + iff.enterChunk(TAG_PRTL); + + VertexList vertexList; + + const int numberOfVertices = iff.read_int32(); + vertexList.reserve(static_cast(numberOfVertices)); + for (int j = 0; j < numberOfVertices; ++j) + vertexList.push_back(iff.read_floatVector()); + + IndexedTriangleList * const portalGeometry = createPortalGeometry(vertexList); + m_portalGeometryList->push_back(portalGeometry); + +#ifdef _DEBUG + validateCoplanar(*portalGeometry, iff.getFileName()); +#endif + + scalePortalVertices(*portalGeometry); + + iff.exitChunk(TAG_PRTL); + } + iff.exitForm(TAG_PRTS); + + // load all the cells + iff.enterForm(TAG_CELS); + m_cellList->reserve(static_cast(numberOfCells)); + for (int j = 0; j < numberOfCells; ++j) + { + Cell *cell = new Cell(*this, j, iff); + m_cellList->push_back(cell); + + if (j > 0) + { + const char *cellName = cell->getName(); + if (cellName) + m_cellNameList->push_back(cellName); + } + } + iff.exitForm(TAG_CELS); + + iff.enterChunk(TAG_CRC); + m_crc = iff.read_int32(); + iff.exitChunk(TAG_CRC); + +#ifdef _DEBUG + { + // verify all the portals have two matches + PortalOwnersList::const_iterator const iEnd = m_portalOwnersList->end(); + for (PortalOwnersList::const_iterator k = m_portalOwnersList->begin(); k != iEnd; ++k) + { + PortalOwners const &owners = *k; + DEBUG_FATAL(owners.owners[0].cell < 0 || owners.owners[0].portal < 0, ("Could not find counter-clockwise owner for portal")); + DEBUG_FATAL(owners.owners[1].cell < 0 || owners.owners[1].portal < 0, ("Could not find clockwise owner for portal")); + } + } +#endif + + iff.exitForm(TAG_0001); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load_0002(Iff &iff) +{ + iff.enterForm(TAG_0002); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + const int numberOfCells = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + // load all the portal geometry + iff.enterForm(TAG_PRTS); + m_portalGeometryList->reserve(static_cast(numberOfPortals)); + m_portalOwnersList->resize(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + { + iff.enterChunk(TAG_PRTL); + + VertexList vertexList; + + const int numberOfVertices = iff.read_int32(); + vertexList.reserve(static_cast(numberOfVertices)); + for (int j = 0; j < numberOfVertices; ++j) + vertexList.push_back(iff.read_floatVector()); + + IndexedTriangleList * const portalGeometry = createPortalGeometry(vertexList); + m_portalGeometryList->push_back(portalGeometry); + +#ifdef _DEBUG + validateCoplanar(*portalGeometry, iff.getFileName()); +#endif + + scalePortalVertices(*portalGeometry); + + iff.exitChunk(TAG_PRTL); + } + iff.exitForm(TAG_PRTS); + + // load all the cells + iff.enterForm(TAG_CELS); + m_cellList->reserve(static_cast(numberOfCells)); + for (int j = 0; j < numberOfCells; ++j) + { + Cell *cell = new Cell(*this, j, iff); + m_cellList->push_back(cell); + + if (j > 0) + { + const char *cellName = cell->getName(); + if (cellName) + m_cellNameList->push_back(cellName); + } + } + iff.exitForm(TAG_CELS); + + if(!iff.atEndOfForm() && iff.getCurrentName() == TAG_PGRF) + { + ObjectFactory pathGraphFactory = FloorManager::getPathGraphFactory(); + + if(pathGraphFactory) + { + BaseClass * pathGraph = pathGraphFactory(iff); + + attachBuildingPathGraph(pathGraph); + } + else + { + // We have a path graph to load but no factory to load it + // with, so skip the form + + iff.enterForm(); + iff.exitForm(true); + } + } + + iff.enterChunk(TAG_CRC); + m_crc = iff.read_int32(); + iff.exitChunk(TAG_CRC); + +#ifdef _DEBUG + { + // verify all the portals have two matches + PortalOwnersList::const_iterator const iEnd = m_portalOwnersList->end(); + for (PortalOwnersList::const_iterator k = m_portalOwnersList->begin(); k != iEnd; ++k) + { + PortalOwners const &owners = *k; + DEBUG_FATAL(owners.owners[0].cell < 0 || owners.owners[0].portal < 0, ("Could not find counter-clockwise owner for portal")); + DEBUG_FATAL(owners.owners[1].cell < 0 || owners.owners[1].portal < 0, ("Could not find clockwise owner for portal")); + } + } +#endif + + iff.exitForm(TAG_0002); + + // ---------- + // Version 2 pobs have their passable flags flipped + + { + for(uint i = 0; i < m_cellList->size(); i++) + { + PortalPropertyTemplateCell * cell = m_cellList->at(i); + + for(uint j = 0; j < cell->m_portalList->size(); j++) + { + PortalPropertyTemplateCellPortal * portal = cell->m_portalList->at(j); + + portal->flipPassable(); + } + } + } +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load_0003(Iff &iff) +{ + iff.enterForm(TAG_0003); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + const int numberOfCells = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + // load all the portal geometry + iff.enterForm(TAG_PRTS); + m_portalGeometryList->reserve(static_cast(numberOfPortals)); + m_portalOwnersList->resize(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + { + iff.enterChunk(TAG_PRTL); + + VertexList vertexList; + + const int numberOfVertices = iff.read_int32(); + vertexList.reserve(static_cast(numberOfVertices)); + for (int j = 0; j < numberOfVertices; ++j) + vertexList.push_back(iff.read_floatVector()); + + IndexedTriangleList * const portalGeometry = createPortalGeometry(vertexList); + m_portalGeometryList->push_back(portalGeometry); + +#ifdef _DEBUG + validateCoplanar(*portalGeometry, iff.getFileName()); +#endif + + scalePortalVertices(*portalGeometry); + + iff.exitChunk(TAG_PRTL); + } + iff.exitForm(TAG_PRTS); + + // load all the cells + iff.enterForm(TAG_CELS); + m_cellList->reserve(static_cast(numberOfCells)); + for (int j = 0; j < numberOfCells; ++j) + { + Cell *cell = new Cell(*this, j, iff); + m_cellList->push_back(cell); + + if (j > 0) + { + const char *cellName = cell->getName(); + if (cellName) + m_cellNameList->push_back(cellName); + } + } + iff.exitForm(TAG_CELS); + + if(!iff.atEndOfForm() && iff.getCurrentName() == TAG_PGRF) + { + ObjectFactory pathGraphFactory = FloorManager::getPathGraphFactory(); + + if(pathGraphFactory) + { + BaseClass * pathGraph = pathGraphFactory(iff); + + attachBuildingPathGraph(pathGraph); + } + else + { + // We have a path graph to load but no factory to load it + // with, so skip the form + + iff.enterForm(); + iff.exitForm(true); + } + } + + iff.enterChunk(TAG_CRC); + m_crc = iff.read_int32(); + iff.exitChunk(TAG_CRC); + +#ifdef _DEBUG + { + // verify all the portals have two matches + PortalOwnersList::const_iterator const iEnd = m_portalOwnersList->end(); + for (PortalOwnersList::const_iterator k = m_portalOwnersList->begin(); k != iEnd; ++k) + { + PortalOwners const &owners = *k; + DEBUG_FATAL(owners.owners[0].cell < 0 || owners.owners[0].portal < 0, ("Could not find counter-clockwise owner for portal")); + DEBUG_FATAL(owners.owners[1].cell < 0 || owners.owners[1].portal < 0, ("Could not find clockwise owner for portal")); + } + } +#endif + + iff.exitForm(TAG_0003); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::load_0004(Iff &iff) +{ + iff.enterForm(TAG_0004); + + iff.enterChunk(TAG_DATA); + const int numberOfPortals = iff.read_int32(); + const int numberOfCells = iff.read_int32(); + iff.exitChunk(TAG_DATA); + + // load all the portal geometry + iff.enterForm(TAG_PRTS); + m_portalGeometryList->reserve(static_cast(numberOfPortals)); + m_portalOwnersList->resize(static_cast(numberOfPortals)); + for (int i = 0; i < numberOfPortals; ++i) + { + IndexedTriangleList * const portalGeometry = new IndexedTriangleList(iff); + m_portalGeometryList->push_back(portalGeometry); + + scalePortalVertices(*portalGeometry); + } + iff.exitForm(TAG_PRTS); + + // load all the cells + iff.enterForm(TAG_CELS); + m_cellList->reserve(static_cast(numberOfCells)); + for (int j = 0; j < numberOfCells; ++j) + { + Cell *cell = new Cell(*this, j, iff); + m_cellList->push_back(cell); + + if (j > 0) + { + const char *cellName = cell->getName(); + if (cellName) + m_cellNameList->push_back(cellName); + } + } + iff.exitForm(TAG_CELS); + + if(!iff.atEndOfForm() && iff.getCurrentName() == TAG_PGRF) + { + ObjectFactory pathGraphFactory = FloorManager::getPathGraphFactory(); + + if(pathGraphFactory) + { + BaseClass * pathGraph = pathGraphFactory(iff); + + attachBuildingPathGraph(pathGraph); + } + else + { + // We have a path graph to load but no factory to load it + // with, so skip the form + + iff.enterForm(); + iff.exitForm(true); + } + } + + iff.enterChunk(TAG_CRC); + m_crc = iff.read_int32(); + iff.exitChunk(TAG_CRC); + +#ifdef _DEBUG + { + // verify all the portals have two matches + PortalOwnersList::const_iterator const iEnd = m_portalOwnersList->end(); + for (PortalOwnersList::const_iterator k = m_portalOwnersList->begin(); k != iEnd; ++k) + { + PortalOwners const &owners = *k; + DEBUG_FATAL(owners.owners[0].cell < 0 || owners.owners[0].portal < 0, ("Could not find counter-clockwise owner for portal")); + DEBUG_FATAL(owners.owners[1].cell < 0 || owners.owners[1].portal < 0, ("Could not find clockwise owner for portal")); + } + } +#endif + + iff.exitForm(TAG_0004); +} + +// ---------------------------------------------------------------------- + +int PortalPropertyTemplate::getCrc() const +{ + return m_crc; +} + +// ---------------------------------------------------------------------- + +int PortalPropertyTemplate::getNumberOfCells() const +{ + return static_cast(m_cellList->size()); +} + +// ---------------------------------------------------------------------- + +const PortalPropertyTemplate::CellNameList &PortalPropertyTemplate::getCellNames() const +{ + NOT_NULL(m_cellNameList); + return *m_cellNameList; +} + +// ---------------------------------------------------------------------- + +const PortalPropertyTemplateCell &PortalPropertyTemplate::getCell(int cellIndex) const +{ + DEBUG_FATAL(cellIndex < 0 || cellIndex >= getNumberOfCells(), ("cell index out of range %d/%d", cellIndex, getNumberOfCells())); + NOT_NULL((*m_cellList)[static_cast(cellIndex)]); + return *(*m_cellList)[static_cast(cellIndex)]; +} + +// ---------------------------------------------------------------------- + +BaseClass const *PortalPropertyTemplate::getBuildingPathGraph() const +{ + return m_pathGraph; +} + +// ---------- + +void PortalPropertyTemplate::attachBuildingPathGraph(BaseClass *newPathGraph) +{ + if(g_expandBuildingGraphHook) + { + delete m_pathGraph; + m_pathGraph = g_expandBuildingGraphHook(this,newPathGraph); + + delete newPathGraph; + } + else + { + if(m_pathGraph != newPathGraph) + { + delete m_pathGraph; + m_pathGraph = newPathGraph; + } + } +} + +// ---------------------------------------------------------------------- + +const char *PortalPropertyTemplate::getExteriorAppearanceName() const +{ + return (*m_cellList)[0]->getAppearanceName(); +} + +// ---------------------------------------------------------------------- + +const char *PortalPropertyTemplate::getExteriorFloorName() const +{ + return (*m_cellList)[0]->getFloorName(); +} + +// ---------------------------------------------------------------------- + +PortalPropertyTemplate::PortalList *PortalPropertyTemplate::createExteriorPortalList(CellProperty *parentCell, Object *relativeToObject) const +{ + return (*m_cellList)[0]->createPortalList(parentCell, relativeToObject); +} + +// ---------------------------------------------------------------------- + +Transform const PortalPropertyTemplate::getEjectionLocationTransform() const +{ + NameTransformMap::iterator const findIt = s_ejectionTransformMap.find(m_name); + if (findIt != s_ejectionTransformMap.end()) + { + //-- Return the data-defined ejection point for this POB. + return findIt->second; + } + else + { + //-- Return the transform for the first door to the outside world, scooted forward a few meters. + Transform result = (*m_cellList)[0]->m_portalList->operator[](0)->getDoorTransform(false); + result.move_l(Vector(0.0f, 0.0f, 5.0f)); + return result; + } +} + +// ---------------------------------------------------------------------- + +const PortalPropertyTemplate::VertexList *PortalPropertyTemplate::getRadarPortalGeometry() const +{ + return m_radarPortalGeometry; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::buildRadarPortalGeometry() +{ + uint i; + for (i = 0; i < m_portalOwnersList->size(); ++i) + { + const PortalPropertyTemplate::PortalOwners& portalOwners = (*m_portalOwnersList)[i]; + if (portalOwners.owners[0].cell == 0 || portalOwners.owners[1].cell == 0) + { + IndexedTriangleList const * const portalGeometry = NON_NULL(getPortalGeometry(static_cast(i))); + std::vector const & vertices = portalGeometry->getVertices(); + std::vector const & indices = portalGeometry->getIndices(); + uint const numberOfFaces = indices.size() / 3; + + if (!m_radarPortalGeometry) + m_radarPortalGeometry = new std::vector; + + for (uint faceIndex = 0, index = 0; faceIndex < numberOfFaces; ++faceIndex) + { + Vector const & v0 = vertices[indices[index++]]; + Vector const & v1 = vertices[indices[index++]]; + Vector const & v2 = vertices[indices[index++]]; + + m_radarPortalGeometry->push_back(v0); + m_radarPortalGeometry->push_back(v1); + m_radarPortalGeometry->push_back(v1); + m_radarPortalGeometry->push_back(v2); + m_radarPortalGeometry->push_back(v2); + m_radarPortalGeometry->push_back(v0); + } + } + } +} + +// ---------------------------------------------------------------------- + +const CrcString &PortalPropertyTemplate::getShortName() const +{ + return m_shortName; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplate::setExpandBuildingGraphHook ( ExpandBuildingGraphHook hook ) +{ + g_expandBuildingGraphHook = hook; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.h b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.h new file mode 100644 index 00000000..6a6999d3 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplate.h @@ -0,0 +1,294 @@ +// ====================================================================== +// +// PortalPropertyTemplate.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PortalPropertyTemplate_H +#define INCLUDED_PortalPropertyTemplate_H + +// ====================================================================== + +class CellProperty; +class FloorMesh; +class Object; +class PortalPropertyTemplate; +class BaseClass; +class BaseExtent; +class Extent; +class IndexedTriangleList; + +#include "sharedMath/Plane.h" +#include "sharedMath/VectorArgb.h" +#include "sharedMath/Transform.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/PersistentCrcString.h" + +// ====================================================================== + +class PortalPropertyTemplateCellPortal +{ + friend class Portal; + +public: + + PortalPropertyTemplateCellPortal(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + ~PortalPropertyTemplateCellPortal(); + + Transform const getDoorTransform(bool useDoorHardpoint=true) const; + + void flipPassable(); + void preloadAssets() const; + void garbageCollect() const; + +private: + + PortalPropertyTemplateCellPortal(); + PortalPropertyTemplateCellPortal(const PortalPropertyTemplateCellPortal &); + PortalPropertyTemplateCellPortal &operator =(const PortalPropertyTemplateCellPortal &); + + void load(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + void load_0001(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + void load_0002(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + void load_0003(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + void load_0004(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + void load_0005(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, int cellPortalIndex, Iff &iff); + + void computePlaneEquation(); + +private: + + bool m_disabled; + bool m_passable; + bool m_geometryWindingClockwise; + IndexedTriangleList const * m_portalGeometry; + char *m_doorStyle; + bool m_hasDoorHardpoint; + Transform m_doorHardpoint; + Plane m_plane; + + class PreloadManager; + friend class PreloadManager; + mutable PreloadManager* m_preloadManager; +}; + +// ---------------------------------------------------------------------- + +struct PortalPropertyTemplateCellLight +{ + enum Type + { + T_ambient, + T_parallel, + T_point + }; + + Type type; + VectorArgb diffuseColor; + VectorArgb specularColor; + Transform transform; + real constantAttenuation; + real linearAttenuation; + real quadraticAttenuation; +}; + +// ---------------------------------------------------------------------- + +class PortalPropertyTemplateCell +{ + friend class PortalProperty; + friend class PortalPropertyTemplate; + +public: + + typedef PortalPropertyTemplateCellLight Light; + typedef stdvector::fwd LightList; + typedef stdvector::fwd PortalList; + typedef stdvector::fwd PortalPropertyTemplateCellPortalList; + +public: + + PortalPropertyTemplateCell(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + ~PortalPropertyTemplateCell(); + + const char *getName() const; + const char *getAppearanceName() const; + const char *getFloorName() const; + FloorMesh const *getFloorMesh() const; + + bool canSeeParentCell() const; + PortalList *createPortalList(CellProperty *parentCell, Object *relativeToObject) const; + const LightList *getLightList() const; + const BaseExtent *getCollisionExtent() const; + + void preloadAssets() const; + void garbageCollect() const; + + const PortalPropertyTemplateCellPortalList *getPortalList() const; + +private: + + void load(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + void load_0001(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + void load_0002(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + void load_0003(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + void load_0004(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + void load_0005(const PortalPropertyTemplate &portalPropertyTemplate, int cellIndex, Iff &iff); + + // disabled + PortalPropertyTemplateCell(PortalPropertyTemplateCell &); + PortalPropertyTemplateCell &operator =(PortalPropertyTemplateCell &); + +private: + + char *m_name; + char *m_appearanceName; + char *m_floorName; + FloorMesh const *m_floorMesh; + bool m_canSeeParentCell; + LightList *m_lightList; + PortalPropertyTemplateCellPortalList *m_portalList; + Extent *m_collisionExtent; + + class PreloadManager; + friend class PreloadManager; + mutable PreloadManager* m_preloadManager; +}; + +//------------------------------------------------------------------------------------------ + +inline const PortalPropertyTemplateCell::PortalPropertyTemplateCellPortalList* PortalPropertyTemplateCell::getPortalList() const +{ + return m_portalList; +} + +// ---------------------------------------------------------------------- + +class PortalPropertyTemplate +{ +public: + + struct PortalOwners + { + struct Owner + { + int cell; + int portal; + + Owner(); + }; + + Owner owners[2]; + }; + + + typedef PortalPropertyTemplateCell Cell; + typedef stdvector::fwd CellList; + typedef stdvector::fwd VertexList; + typedef stdvector::fwd PortalList; + typedef stdvector::fwd PortalOwnersList; + typedef stdvector::fwd PortalGeometryList; + typedef stdvector::fwd CellNameList; + +public: + + static void install(char const *const pobEjectionTransformFilename); + + static bool extractPortalLayoutCrc(const char *fileName, uint32 &portalLayoutCrc); + +public: + + explicit PortalPropertyTemplate(const CrcString &name); + ~PortalPropertyTemplate(); + + void fetch() const; + void release() const; + + void preloadAssets() const; + void garbageCollect() const; + + const CrcString &getCrcString() const; + const CrcString &getShortName() const; + + int getCrc() const; + int getNumberOfCells() const; + const CellNameList &getCellNames() const; + + const char *getExteriorAppearanceName() const; + const char *getExteriorFloorName() const; + PortalList *createExteriorPortalList(CellProperty *parentCell, Object *relativeToObject) const; + Transform const getEjectionLocationTransform() const; + + IndexedTriangleList const * getPortalGeometry(int portalIndex) const; + IndexedTriangleList const * getPortalGeometry(int portalIndex, int cell, int cellPortalIndex, bool clockwise) const; + const PortalPropertyTemplateCell &getCell(int cellIndex) const; + + PortalOwnersList const &getPortalOwnersList() const; + + BaseClass const *getBuildingPathGraph() const; + void attachBuildingPathGraph(BaseClass *newGraph); + + const VertexList *getRadarPortalGeometry() const; + + typedef BaseClass * (*ExpandBuildingGraphHook)( PortalPropertyTemplate * portalTemplate, BaseClass * baseBuildingGraph ); + + static void setExpandBuildingGraphHook ( ExpandBuildingGraphHook hook ); + +private: + + // disabled + PortalPropertyTemplate(); + PortalPropertyTemplate(const PortalPropertyTemplate &); + PortalPropertyTemplate &operator =(const PortalPropertyTemplate &); + + void load(Iff &iff); + void load_0000(Iff &iff); + void load_0001(Iff &iff); + void load_0002(Iff &iff); + void load_0003(Iff &iff); + void load_0004(Iff &iff); + + void buildRadarPortalGeometry(); + +private: + + mutable int m_referenceCount; + PersistentCrcString m_name; + PersistentCrcString m_shortName; + PortalGeometryList *m_portalGeometryList; + PortalOwnersList *m_portalOwnersList; + CellList *m_cellList; + CellNameList *m_cellNameList; + int m_crc; + BaseClass *m_pathGraph; + VertexList *m_radarPortalGeometry; +}; + + + +// ====================================================================== + +inline void PortalPropertyTemplate::fetch() const +{ + ++m_referenceCount; +} + +// ---------------------------------------------------------------------- + +inline const CrcString &PortalPropertyTemplate::getCrcString() const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +inline PortalPropertyTemplate::PortalOwnersList const &PortalPropertyTemplate::getPortalOwnersList() const +{ + return *m_portalOwnersList; +} + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.cpp b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.cpp new file mode 100644 index 00000000..e5deffc3 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.cpp @@ -0,0 +1,81 @@ +// ====================================================================== +// +// PortalPropertyTemplateList.cpp +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/PortalPropertyTemplateList.h" + +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/LessPointerComparator.h" +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedObject/PortalPropertyTemplate.h" + +#include +#include + +// ====================================================================== + +namespace PortalPropertyTemplateListNamespace +{ + typedef std::map TemplateList; + + void remove(); + + static bool ms_installed; + static TemplateList ms_templateList; +} + +using namespace PortalPropertyTemplateListNamespace; + +// ====================================================================== + +void PortalPropertyTemplateList::install() +{ + DEBUG_FATAL(ms_installed, ("double install")); + ms_installed = true; + ExitChain::add(remove, "PortalPropertyTemplateListImp::remove"); +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateListNamespace::remove() +{ + DEBUG_FATAL(!ms_templateList.empty(), ("%d PortalPropertyTemplates still allocated", static_cast(ms_templateList.size()))); +} + +// ---------------------------------------------------------------------- + +const PortalPropertyTemplate *PortalPropertyTemplateList::fetch(const CrcString &name) +{ + PortalPropertyTemplate *result; + + TemplateList::iterator i = ms_templateList.find(&name); + if (i == ms_templateList.end()) + { + result = new PortalPropertyTemplate(name); + const bool inserted = ms_templateList.insert(TemplateList::value_type(&result->getCrcString(), result)).second; + UNREF(inserted); + DEBUG_FATAL(!inserted, ("item was already present")); + } + else + result = i->second; + + result->fetch(); + return result; +} + +// ---------------------------------------------------------------------- + +void PortalPropertyTemplateList::erase(const PortalPropertyTemplate &portalPropertyTemplate) +{ + TemplateList::iterator i = ms_templateList.find(&portalPropertyTemplate.getCrcString()); + DEBUG_FATAL(i == ms_templateList.end(), ("item not found")); + ms_templateList.erase(i); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.h b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.h new file mode 100644 index 00000000..de679a7c --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortalPropertyTemplateList.h @@ -0,0 +1,35 @@ +// ====================================================================== +// +// PortalPropertyTemplateList.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PortalPropertyTemplateList_H +#define INCLUDED_PortalPropertyTemplateList_H + +// ====================================================================== + +class CrcString; + +// ====================================================================== + +class PortalPropertyTemplateList +{ + friend class PortalPropertyTemplate; + +public: + + static void install(); + + static const PortalPropertyTemplate *fetch(const CrcString &crcLowerString); + +private: + + static void erase(const PortalPropertyTemplate &portalPropertyTemplate); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/portal/PortallizedSphereTree.h b/engine/shared/library/sharedObject/src/shared/portal/PortallizedSphereTree.h new file mode 100644 index 00000000..7d91f252 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/PortallizedSphereTree.h @@ -0,0 +1,480 @@ +// ====================================================================== +// +// PortallizedSphereTree.h +// +// Copyright 2004 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_PortallizedSphereTree_H +#define INCLUDED_PortallizedSphereTree_H + +// ====================================================================== +// +// PortallizedSphereTree is a spatial organization class which keeps +// objects grouped in the space of the pob containing them, such that +// the structure only needs to be updated for objects that move +// relative to their parent. +// +// For each pob with a containing object added to the PortallizedSphereTree, +// there is a SphereTree of the objects in that pob, kept in the local +// space of the pob. There is also an equivalent separate tree of objects +// in the world cell. We then keep a SphereTree of the pobs themselves, +// which references the tree for the pob, whose spheres are the containing +// spheres for the SphereTree for the individual pob, in world space. +// +// A PortallizedSphereTree should be set up such +// that Accessor is a derived class of PortallizedSphereTreeAccessor +// . It should additionally provide, at a minimum, +// static Sphere const getExtent(ObjectType object); +// static Object const *getCurrentPob(ObjectType object); +// These do not need to be exact signature matches, only assignment-compatible +// functions. getExtent should return the extent sphere for object, in +// parent space. getCurrentPob should return the containing pob whose space +// object is in, or 0 for world cell objects. +// +// A PortallizedSphereTree should be updated when an object should be +// added to it, or an object already in it should be removed or moved, +// via the onObjectAdded, onObjectRemoved, and onObjectMoved members. +// +// Searching the tree should be done via the various findInRange members. +// +// ====================================================================== + +#include "sharedFoundation/Watcher.h" +#include "sharedMath/Capsule.h" +#include "sharedMath/SphereTree.h" + +// ====================================================================== + +class Object; + +// ====================================================================== + +template +class PortallizedSphereTreeNodeHandle: public SphereTreeNode::NodeHandle +{ +public: + + PortallizedSphereTreeNodeHandle() : + SphereTreeNode::NodeHandle(), + m_storedPob(0) + { + } + + Object const *getStoredPob() const + { + return m_storedPob; + } + + void setStoredPob(Object const *pob) + { + m_storedPob = pob; + } + +private: + Object const *m_storedPob; +}; + +// ====================================================================== + +template +class PortallizedSphereTree +{ +public: + PortallizedSphereTree(); + ~PortallizedSphereTree(); + + void onObjectAdded(ObjectType object); + void onObjectRemoved(ObjectType object); + void onObjectMoved(ObjectType object); + + // search functions which check multiple pobs + void findInRange(Vector const ¢er_w, float radius, std::vector &results) const; + void findInRange(Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::vector &results) const; + void findInRange(Capsule const &queryCapsule_w, std::vector &results) const; + void findInRange(Capsule const &queryCapsule_w, SpatialSubdivisionFilter const &filter, std::vector &results) const; + // search functions which check a single pob + void findInRange(Object const *pob, Vector const ¢er_p, float radius, std::vector &results) const; + void findInRange(Object const *pob, Vector const ¢er_p, float radius, SpatialSubdivisionFilter const &filter, std::vector &results) const; + + void dumpSphereTree(std::vector > &results) const; + +private: + PortallizedSphereTree(PortallizedSphereTree const &); + PortallizedSphereTree &operator=(PortallizedSphereTree const &); + + class PobContentsInfo; + + class PobTreeAccessor: public BaseSphereTreeAccessor + { + public: + static Sphere const getExtent(PobContentsInfo const *pct) + { + Sphere const &localSphere = pct->contents.getRealSphere(); + Object const * const pob = pct->getPob(); + DEBUG_FATAL(!pob, ("Tried to get the extent for a pob which no longer exists. This should have been caught earlier.")); + if (pob) + { + Transform const &transform = pob->getTransform_o2p(); + return Sphere(transform.rotateTranslate_l2p(localSphere.getCenter()), localSphere.getRadius()); + } + return localSphere; + } + }; + + typedef SphereTree PobContentsTree; + typedef PortallizedSphereTreeNodeHandle PobContentsTreeNodeHandle; + typedef typename SphereTreeNode::NodeHandle PobTreeNodeHandle; + typedef SphereTree PobTree; + typedef std::map PobContentsInfoMap; + + class PobContentsInfo + { + public: + PobContentsInfo(Object const *newPob) : + nodeHandle(0), + pobWatcher(newPob), + contents() + { + } + + Object const *getPob() const + { + return pobWatcher.getPointer(); + } + + bool isPobEmpty() const + { + return !pobWatcher.getPointer() || contents.empty(); + } + + PobTreeNodeHandle *nodeHandle; + ConstWatcher pobWatcher; + PobContentsTree contents; + + private: + PobContentsInfo(PobContentsInfo const &); + PobContentsInfo &operator=(PobContentsInfo const &); + }; + + void onObjectAddedInternal(ObjectType object, Object const *pob); + void onObjectRemovedInternal(ObjectType object, PobContentsTreeNodeHandle *objectNodeHandle, Object const *oldPob); + + PobContentsInfoMap m_pobContentsInfoMap; + PobTree m_pobTree; + PobContentsTree m_worldCellContentsTree; +}; + +// ---------------------------------------------------------------------- + +template +PortallizedSphereTree::PortallizedSphereTree() : + m_pobContentsInfoMap(), + m_pobTree() +{ +} + +// ---------------------------------------------------------------------- + +template +PortallizedSphereTree::~PortallizedSphereTree() +{ + for (typename PobContentsInfoMap::const_iterator i = m_pobContentsInfoMap.begin(); i != m_pobContentsInfoMap.end(); ++i) + delete (*i).second; + m_pobContentsInfoMap.clear(); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::onObjectAdded(ObjectType object) +{ + onObjectAddedInternal(object, Accessor::getCurrentPob(object)); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::onObjectAddedInternal(ObjectType object, Object const *pob) +{ + if (!pob) + { + // object in the world cell + PobContentsTreeNodeHandle * const objectNodeHandle = static_cast(m_worldCellContentsTree.addObject(object)); + Accessor::setNodeHandle(object, objectNodeHandle); + objectNodeHandle->setStoredPob(0); + } + else + { + // object not in the world cell + typename PobContentsInfoMap::iterator i = m_pobContentsInfoMap.lower_bound(pob); + if (i == m_pobContentsInfoMap.end() || (*i).first != pob) + { + // This pob did not have a PobContentsInfo in the map, so create one, + // add it to the map and pob tree, and set the iterator to the new + // entry in the map + PobContentsInfo * const newPobContentsInfo = new PobContentsInfo(pob); + i = m_pobContentsInfoMap.insert(i, std::make_pair(pob, newPobContentsInfo)); + newPobContentsInfo->nodeHandle = static_cast(m_pobTree.addObject(newPobContentsInfo)); + } + + PobContentsInfo * const pobContentsInfo = (*i).second; + + // Add the object to the contents tree for this pob + PobContentsTreeNodeHandle * const objectNodeHandle = static_cast(pobContentsInfo->contents.addObject(object)); + Accessor::setNodeHandle(object, objectNodeHandle); + objectNodeHandle->setStoredPob(pob); + + // Update the pob tree node since its extents may have changed + pobContentsInfo->nodeHandle->move(); + } +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::onObjectRemoved(ObjectType object) +{ + PobContentsTreeNodeHandle * const objectNodeHandle = Accessor::getNodeHandle(object); + if (objectNodeHandle) + onObjectRemovedInternal(object, objectNodeHandle, objectNodeHandle->getStoredPob()); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::onObjectRemovedInternal(ObjectType object, PobContentsTreeNodeHandle *objectNodeHandle, Object const * oldPob) +{ + if (!oldPob) + { + // object was in the world cell + objectNodeHandle->removeObject(); + Accessor::setNodeHandle(object, 0); + } + else + { + // object was not in the world cell, but may potentially have been in a pob which has been deleted + typename PobContentsInfoMap::iterator i = m_pobContentsInfoMap.find(oldPob); + if (i == m_pobContentsInfoMap.end()) + Accessor::setNodeHandle(object, 0); + else + { + // remove object from the sphere tree for the pob + objectNodeHandle->removeObject(); + Accessor::setNodeHandle(object, 0); + + if ((*i).second->isPobEmpty()) + { + // if it was the last object in the pob, remove the pob from the pob tree + (*i).second->nodeHandle->removeObject(); + delete (*i).second; + m_pobContentsInfoMap.erase(i); + } + else + { + // there are still objects in the pob, so update the pob's sphere + (*i).second->nodeHandle->move(); + } + } + } +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::onObjectMoved(ObjectType object) +{ + PobContentsTreeNodeHandle * const objectNodeHandle = Accessor::getNodeHandle(object); + if (objectNodeHandle) + { + Object const * const startPob = objectNodeHandle->getStoredPob(); + Object const * const endPob = Accessor::getCurrentPob(object); + + if (startPob == endPob) + { + // staying in the same parent space, so notify the object node that it moved + objectNodeHandle->move(); + // if not in the world pob, moving a contained object may change the extents in the pob tree + if (startPob) + { + typename PobContentsInfoMap::iterator i = m_pobContentsInfoMap.find(startPob); + FATAL(i == m_pobContentsInfoMap.end(), ("Tried to move an object within a pob not in the tree")); + (*i).second->nodeHandle->move(); + } + } + else + { + // changing parent spaces + onObjectRemovedInternal(object, objectNodeHandle, startPob); + onObjectAddedInternal(object, endPob); + } + } +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Vector const ¢er_w, float radius, std::vector &results) const +{ + m_worldCellContentsTree.findInRange(center_w, radius, results); + + static std::vector pobResults; + m_pobTree.findInRange(center_w, radius, pobResults); + for (typename std::vector::const_iterator i = pobResults.begin(); i != pobResults.end(); ++i) + { + Object const * const pob = (*i)->getPob(); + if (pob) + (*i)->contents.findInRange(pob->getTransform_o2p().rotateTranslate_p2l(center_w), radius, results); + } + pobResults.clear(); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::vector &results) const +{ + m_worldCellContentsTree.findInRange(center_w, radius, filter, results); + + static std::vector pobResults; + m_pobTree.findInRange(center_w, radius, pobResults); + for (typename std::vector::const_iterator i = pobResults.begin(); i != pobResults.end(); ++i) + { + Object const * const pob = (*i)->getPob(); + if (pob) + (*i)->contents.findInRange(pob->getTransform_o2p().rotateTranslate_p2l(center_w), radius, filter, results); + } + pobResults.clear(); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Capsule const &queryCapsule_w, std::vector &results) const +{ + m_worldCellContentsTree.findInRange(queryCapsule_w, results); + + static std::vector pobResults; + m_pobTree.findInRange(queryCapsule_w, pobResults); + if (!pobResults.empty()) + { + Vector const &querySphereCenter_w = queryCapsule_w.getCenter(); + float const querySphereRadius = queryCapsule_w.getTotalRadius(); + for (typename std::vector::const_iterator i = pobResults.begin(); i != pobResults.end(); ++i) + { + Object const * const pob = (*i)->getPob(); + if (pob) + (*i)->contents.findInRange(pob->getTransform_o2p().rotateTranslate_p2l(querySphereCenter_w), querySphereRadius, results); + } + } + pobResults.clear(); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Capsule const &queryCapsule_w, SpatialSubdivisionFilter const &filter, std::vector &results) const +{ + m_worldCellContentsTree.findInRange(queryCapsule_w, filter, results); + + static std::vector pobResults; + m_pobTree.findInRange(queryCapsule_w, pobResults); + if (!pobResults.empty()) + { + Vector const &querySphereCenter_w = queryCapsule_w.getCenter(); + float const querySphereRadius = queryCapsule_w.getTotalRadius(); + for (typename std::vector::const_iterator i = pobResults.begin(); i != pobResults.end(); ++i) + { + Object const * const pob = (*i)->getPob(); + if (pob) + (*i)->contents.findInRange(pob->getTransform_o2p().rotateTranslate_p2l(querySphereCenter_w), querySphereRadius, filter, results); + } + } + pobResults.clear(); +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Object const *pob, Vector const ¢er_p, float radius, std::vector &results) const +{ + if (!pob) + m_worldCellContentsTree.findInRange(center_p, radius, results); + else + { + typename PobContentsInfoMap::const_iterator i = m_pobContentsInfoMap.find(pob); + if (i != m_pobContentsInfoMap.end()) + (*i).second->contents.findInRange(center_p, radius, results); + } +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::findInRange(Object const *pob, Vector const ¢er_p, float radius, SpatialSubdivisionFilter const &filter, std::vector &results) const +{ + if (!pob) + m_worldCellContentsTree.findInRange(center_p, radius, filter, results); + else + { + typename PobContentsInfoMap::const_iterator i = m_pobContentsInfoMap.find(pob); + if (i != m_pobContentsInfoMap.end()) + (*i).second->contents.findInRange(center_p, radius, filter, results); + } +} + +// ---------------------------------------------------------------------- + +template +void PortallizedSphereTree::dumpSphereTree(std::vector > &results) const +{ + m_worldCellContentsTree.dumpSphereTree(results); + + for (typename PobContentsInfoMap::const_iterator i = m_pobContentsInfoMap.begin(); i != m_pobContentsInfoMap.end(); ++i) + { + Object const * const pob = (*i).second->getPob(); + if (pob) + { + std::vector > tempResults; + (*i).second->contents.dumpSphereTree(tempResults); + for (typename std::vector >::iterator j = tempResults.begin(); j != tempResults.end(); ++j) + { + (*j).second.setCenter(pob->getTransform_o2p().rotateTranslate_l2p((*j).second.getCenter())); + results.push_back(*j); + } + } + } +} + +// ====================================================================== + +template +class PortallizedSphereTreeAccessor +{ +public: + // derived classes need to implement the following - types need only be assignement-compatible, not exact: + // static Sphere const getExtent(ObjectType object); + // static Object const *getCurrentPob(ObjectType object); + + static PortallizedSphereTreeNodeHandle *getNodeHandle(ObjectType object) + { + return static_cast *>(object->getSpatialSubdivisionHandle()); + } + + static void setNodeHandle(ObjectType object, SpatialSubdivisionHandle *nodeHandle) + { + object->setSpatialSubdivisionHandle(nodeHandle); + } + + static typename SphereTreeNode::NodeHandle *allocateNodeHandle() + { + return new PortallizedSphereTreeNodeHandle(); + } + +}; + +// ====================================================================== + +#endif // INCLUDED_PortallizedSphereTree_H + diff --git a/engine/shared/library/sharedObject/src/shared/portal/SphereGrid.h b/engine/shared/library/sharedObject/src/shared/portal/SphereGrid.h new file mode 100644 index 00000000..00a1ea37 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/portal/SphereGrid.h @@ -0,0 +1,559 @@ +// SphereGrid.h +// Copyright 2000-05, Sony Online Entertainment Inc., all rights reserved. +// Author: Neal Kettler + +#ifndef _INCLUDED_SphereGrid_H +#define _INCLUDED_SphereGrid_H + +//----------------------------------------------------------------------- + +#include "sharedMath/Sphere.h" +#include "sharedMath/Capsule.h" +#include "sharedMath/SpatialSubdivision.h" +#include "sharedLog/Log.h" + +#include +#include +#include + +class Object; + + +#define INVALID_POB ((const Object*)0xFFFFFFFF) + + +// +// SphereGrid - Sorts spheres into a grid of GridSize x GridSize units. This allows +// fairly quick collision searches for things like trigger volumes. +// +// If an object is on a grid boundry it may reside in multiple grids at the same time. +// Objects are tracked in worldspace so portals are handled automatically. +// +template +class SphereGrid +{ +public: + SphereGrid(float GridSize = 100.0, float GridMaxDimension = 20000.0) : + m_fGridSize( GridSize ), + m_fGridMaxDimension( GridMaxDimension ), + m_iGridSquareWidth( (int)((GridMaxDimension * 2.0f) / GridSize) ) + {}; + + + void onObjectAdded( ObjectType object); + void onObjectRemoved( ObjectType object); + void onObjectMoved( ObjectType object ); + + // search functions which check multiple pobs + void findInRange( Vector const ¢er_w, float radius, std::set &results); + void findInRange(Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set &results); + void findInRange( Capsule const &queryCapsule_w, std::set &results); + void findInRange(Capsule const &queryCapsule_w, SpatialSubdivisionFilter const &filter, std::set &results); + + // search functions which check a single pob + void findInRange(Object const *pob, Vector const ¢er_p, float radius, std::set &results); + void findInRange(Object const *pob, Vector const ¢er_p, float radius, SpatialSubdivisionFilter const &filter, std::set &results); + + //////////////void dumpSphereTree(std::vector > &results) const; + +private: + + SphereGrid(SphereGrid const &); + SphereGrid &operator=(SphereGrid const &); + + void findInRangeSphere( Object const *pob, Vector const ¢er_w, float radius, SpatialSubdivisionFilter const *filter, std::set &results); + void findInRangeCapsule( Object const *pob, Capsule const &queryCapsule_w, SpatialSubdivisionFilter const *filter, std::set &results); + + + void getContainingSquares(const Capsule & range, std::vector & results) const; + void getContainingSquares( const Sphere& sphere, std::vector& results) const; + + + int getSquare( const Vector& point ) const + { + int z = int((point.z + m_fGridMaxDimension) / m_fGridSize); + int x = int((point.x + m_fGridMaxDimension) / m_fGridSize); + int square = (m_iGridSquareWidth * z) + x; + return square; + } + + std::map< int , std::set< ObjectType > > m_contents; // map from square_id -> object list + + std::map< ObjectType, Vector > m_locations; // last location of known objects + + const float m_fGridSize; + const float m_fGridMaxDimension; + const int m_iGridSquareWidth; + +}; + + + +// +// Add object to grid squares +// +template +inline void SphereGrid::onObjectAdded(ObjectType object) +{ + const Sphere & sphere = Accessor::getExtent(object); + if(sphere.getRadius() <= 0.0f) + return; + + + // Vector c = sphere.getCenter(); + // LOG("SphereGrid",( "Adding Object (%f %f %f) R = %f O = %p", c.x, c.y, c.z, sphere.getRadius(), object )); + + m_locations[ object ] = sphere.getCenter(); + + std::vector< int > squares; + getContainingSquares(sphere, squares); + + + std::vector< int >::iterator square_iter; + for( square_iter = squares.begin(); square_iter != squares.end(); ++square_iter ) + { + m_contents[ *square_iter ].insert( object ); + } +} + + + +template +inline void SphereGrid< ObjectType, Accessor>::onObjectRemoved(ObjectType object) +{ + int i_num_removed = 0; + Sphere sphere = Accessor::getExtent(object); + + Vector& loc=m_locations[object]; + sphere.setCenter( loc ); + + // LOG("SphereGrid", ("Removing object R = %f O = %p", sphere.getRadius(), object ) ); + + std::vector< int > squares; + getContainingSquares(sphere, squares); + std::vector< int >::iterator square_iter; + for( square_iter = squares.begin(); square_iter != squares.end(); ++square_iter ) + { + std::set< ObjectType >& object_set = ( m_contents[ *square_iter ] ) ; + typename std::set< ObjectType >::iterator iter = object_set.find( object ); + if ( iter != object_set.end() ) + { + object_set.erase( iter ); + ++i_num_removed; + } + else + { + DEBUG_FATAL(true, ("SphereGrid::onObjectRemoved, couldn't find object to remove! %p",object)); + } + } + + // LOG("SphereGrid", ("Num removed O = %p Num=%d", object, i_num_removed ) ); + + m_locations.erase( object ); +} + + + +// +// Object moved - make sure it's in the proper grid squares now +// +template +inline void SphereGrid< ObjectType, Accessor>::onObjectMoved( ObjectType object ) +{ + + Sphere end_sphere = Accessor::getExtent(object); + Sphere start_sphere( end_sphere ); + + Vector& start=m_locations[object]; + + start_sphere.setCenter( start ); + + std::vector< int > start_squares; + std::vector< int > end_squares; + + getContainingSquares(start_sphere, start_squares); + getContainingSquares(end_sphere, end_squares); + + if ( start_squares == end_squares ) + return; // nothing to do... + + // Remove from old squares, then add to new squares + std::vector< int >::iterator square_iter; + + for ( square_iter = start_squares.begin(); square_iter != start_squares.end(); ++square_iter ) + { + std::set< ObjectType >& set = ( m_contents[ *square_iter ] ); + typename std::set< ObjectType >::iterator iter = set.find( object ); + if ( iter == set.end() ) + { + DEBUG_FATAL(true, ("SphereGrid::onObjectMoved, couldn't find object to move! %p",object)); + } + else + { + set.erase( iter ); + } + } + for ( square_iter = end_squares.begin(); square_iter != end_squares.end(); ++square_iter ) + { + std::set< ObjectType >& set = ( m_contents[ *square_iter ] ); + set.insert( object ); + } + + m_locations[object] = end_sphere.getCenter(); +} + + +// +// Get a list of all the squares needed to contain this capsule +// +template +inline void SphereGrid::getContainingSquares(const Capsule & range, std::vector & results) const +{ + Sphere bounds = range.getBoundingSphere(); + Vector b_center = bounds.getCenter(); + float b_rad = bounds.getRadius(); + Vector b_min( b_center.x - b_rad, 0, b_center.z - b_rad); + Vector b_max( b_center.x + b_rad, 0, b_center.z + b_rad); + int squaremin = getSquare(b_min); + int squaremax = getSquare(b_max); + if ( squaremin == squaremax ) + { + results.push_back(squaremin); + return; + } + + int xmin = int((b_min.x + m_fGridMaxDimension) / m_fGridSize); + int xmax = int((b_max.x + m_fGridMaxDimension) / m_fGridSize); + int zmin = int((b_min.z + m_fGridMaxDimension) / m_fGridSize); + int zmax = int((b_max.z + m_fGridMaxDimension) / m_fGridSize); + + float sqrt_two = float(sqrt( 2.0 )); + for ( int z = zmin; z <= zmax; ++z ) + { + for ( int x = xmin; x <= xmax; ++x ) + { + int square = int(m_iGridSquareWidth * z) + x; + + // Create a sphere that contains the square (makes collision simpler) + Sphere squarebounds( float((x*m_fGridSize) - m_fGridMaxDimension) + float(m_fGridSize/2.0), b_center.y, float((z*m_fGridSize) - m_fGridMaxDimension) + float(m_fGridSize/2.0), float(m_fGridSize/2.0) * sqrt_two ); + if ( range.intersectsSphere( squarebounds )) // range-->bounds + results.push_back( square ); + } + } +} + + + +// +// Get a list of all the squares needed to contain this sphere +// +template +inline void SphereGrid::getContainingSquares(const Sphere & bounds, std::vector & results) const +{ + Vector b_center = bounds.getCenter(); + float b_rad = bounds.getRadius(); + Vector b_min( b_center.x - b_rad, 0, b_center.z - b_rad); + Vector b_max( b_center.x + b_rad, 0, b_center.z + b_rad); + int squaremin = getSquare(b_min); + int squaremax = getSquare(b_max); + if ( squaremin == squaremax ) + { + results.push_back(squaremin); + return; + } + + int xmin = int((b_min.x + m_fGridMaxDimension) / m_fGridSize); + int xmax = int((b_max.x + m_fGridMaxDimension) / m_fGridSize); + int zmin = int((b_min.z + m_fGridMaxDimension) / m_fGridSize); + int zmax = int((b_max.z + m_fGridMaxDimension) / m_fGridSize); + + float sqrt_two = float(sqrt( 2.0 )); + for ( int z = zmin; z <= zmax; ++z ) + { + for ( int x = xmin; x <= xmax; ++x ) + { + int square = int(m_iGridSquareWidth * z) + x; + + // Create a sphere that contains the square (makes collision simpler) + Sphere squarebounds( float((x*m_fGridSize) - m_fGridMaxDimension) + float(m_fGridSize/2.0), b_center.y, float((z*m_fGridSize) - m_fGridMaxDimension) + float(m_fGridSize/2.0), float(m_fGridSize/2.0) * sqrt_two ); + if ( bounds.intersectsSphere( squarebounds )) + results.push_back( square ); + } + } +} + + +// +// Common private method called by all findInRange() public methods using a sphere +// +template +inline void SphereGrid::findInRangeSphere( Object const *pob, Vector const ¢er_w, float radius, + SpatialSubdivisionFilter const *filter, std::set &results) +{ + Sphere range(center_w, radius); + std::vector< int > squares; + getContainingSquares( range, squares ); + std::vector< int >::iterator citer; + for ( citer = squares.begin(); citer != squares.end(); ++citer ) + { + typename std::set< ObjectType >::const_iterator oiter; + int square_id = *citer; + std::set< ObjectType >& objects = m_contents[ square_id ]; // objects in this square + + for ( oiter = objects.begin(); oiter != objects.end(); ++oiter ) + { + Sphere sphere = ExtentAccessor::getExtent( *oiter ); + + + if ( range.intersectsSphere( sphere)) + { + if ( pob != INVALID_POB ) + { + Object const* thispob = ExtentAccessor::getCurrentPob( *oiter ); + if ( pob != thispob ) + continue; + } + if (( filter ) && ( ! (*filter)(*oiter) )) + { + continue; + } + + + results.insert(*oiter); + } + } + } +} + + + +// +// Common private method called by all findInRange() public methods using a capsule +// +template +inline void SphereGrid::findInRangeCapsule( Object const *pob, Capsule const &range, + SpatialSubdivisionFilter const *filter, std::set &results) +{ + std::vector< int > squares; + getContainingSquares( range, squares ); + std::vector< int >::iterator citer; + for ( citer = squares.begin(); citer != squares.end(); ++citer ) + { + typename std::set< ObjectType >::const_iterator oiter; + int square_id = *citer; + std::set< ObjectType >& objects = m_contents[ square_id ]; // objects in this square + + for ( oiter = objects.begin(); oiter != objects.end(); ++oiter ) + { + Sphere sphere = ExtentAccessor::getExtent( *oiter ); + + + if ( range.intersectsSphere( sphere)) + { + + if ( pob != INVALID_POB ) + { + Object const* thispob = ExtentAccessor::getCurrentPob( *oiter ); + if ( pob != thispob ) + continue; + } + if (( filter ) && ( ! (*filter)(*oiter) )) + { + continue; + } + + + results.insert(*oiter); + } + } + } +} + + +template +inline void SphereGrid::findInRange( const Capsule & range, std::set & results) +{ + findInRangeCapsule( INVALID_POB, range, NULL, results ); +} + + +template +inline void SphereGrid::findInRange( Vector const ¢er_w, float radius, std::set & results) +{ + findInRangeSphere( INVALID_POB, center_w, radius, NULL, results ); +} + + +template +inline void SphereGrid::findInRange( const Capsule & range, SpatialSubdivisionFilter const &filter, std::set & results) +{ + findInRangeCapsule( INVALID_POB, range, &filter, results ); +} + + +template +inline void SphereGrid::findInRange( Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set & results) +{ + findInRangeSphere( INVALID_POB, center_w, radius, &filter, results ); +} + + +template +inline void SphereGrid::findInRange( Object const *pob, Vector const ¢er_w, float radius, std::set & results) +{ + findInRangeSphere( pob, center_w, radius, NULL, results ); +} + +template +inline void SphereGrid::findInRange( Object const *pob, Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set & results) +{ + findInRangeSphere( pob, center_w, radius, &filter, results ); +} + + + +// +// DoubleSphereGrid - This class maintains two SphereGrid instances at different scales. +// Certain objects have very large collision spheres that cover dozens of grid squares. By using a seperate +// sphere grid with a larger square size we can reduce the number of duplicate entries in the square contents tables. +// +template +class DoubleSphereGrid +{ +public: + DoubleSphereGrid() : + m_largeGrid(250.0), // native grid size in meters + m_smallGrid(100.0), + m_fMaxSmallSize( 150.0 ) + {} + + void onObjectAdded(ObjectType object); + void onObjectRemoved(ObjectType object); + void onObjectMoved(ObjectType object ); + + // search functions which check multiple pobs + void findInRange( Vector const ¢er_w, float radius, std::set &results); // const; + void findInRange(Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set &results); + void findInRange( Capsule const &queryCapsule_w, std::set &results); + void findInRange(Capsule const &queryCapsule_w, SpatialSubdivisionFilter const &filter, std::set &results); + + // search functions which check a single pob + void findInRange(Object const *pob, Vector const ¢er_p, float radius, std::set &results); + void findInRange(Object const *pob, Vector const ¢er_p, float radius, SpatialSubdivisionFilter const &filter, std::set &results); + + //////////////void dumpSphereTree(std::vector > &results) const; + +private: + + DoubleSphereGrid(DoubleSphereGrid const &); + DoubleSphereGrid &operator=(DoubleSphereGrid const &); + + SphereGrid< ObjectType, Accessor> m_largeGrid; + SphereGrid< ObjectType, Accessor> m_smallGrid; + const float m_fMaxSmallSize; +}; + + + + + +template +inline void DoubleSphereGrid::onObjectAdded(ObjectType object) +{ + const Sphere & sphere = Accessor::getExtent(object); + if ( sphere.getRadius() > m_fMaxSmallSize ) + { + m_largeGrid.onObjectAdded( object ); + } + else + { + m_smallGrid.onObjectAdded( object ); + } +} + +template +inline void DoubleSphereGrid::onObjectRemoved(ObjectType object) +{ + const Sphere & sphere = Accessor::getExtent(object); + if ( sphere.getRadius() > m_fMaxSmallSize ) + { + m_largeGrid.onObjectRemoved( object ); + } + else + { + m_smallGrid.onObjectRemoved( object ); + } +} + + +template +inline void DoubleSphereGrid::onObjectMoved( ObjectType object ) +{ + const Sphere & sphere = Accessor::getExtent(object); + if ( sphere.getRadius() > m_fMaxSmallSize ) + { + m_largeGrid.onObjectMoved( object ); + } + else + { + m_smallGrid.onObjectMoved( object ); + } +} + + + +template +inline void DoubleSphereGrid::findInRange( const Capsule & range, std::set & results) +{ + m_largeGrid.findInRange( range, results ); + m_smallGrid.findInRange( range, results ); +} + + +template +inline void DoubleSphereGrid::findInRange(Vector const ¢er_w, float radius, std::set & results) +{ + m_largeGrid.findInRange( center_w, radius, results); + m_smallGrid.findInRange( center_w, radius, results); +} + + +template +inline void DoubleSphereGrid::findInRange( const Capsule & range, SpatialSubdivisionFilter const &filter, std::set & results) +{ + m_largeGrid.findInRange( range, filter, results ); + m_smallGrid.findInRange( range, filter, results ); +} + + +template +inline void DoubleSphereGrid::findInRange(Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set & results) +{ + m_largeGrid.findInRange( center_w, radius, filter, results); + m_smallGrid.findInRange( center_w, radius, filter, results); +} + + +template +inline void DoubleSphereGrid::findInRange(Object const *pob, Vector const ¢er_w, float radius, std::set & results) +{ + m_largeGrid.findInRange(pob, center_w, radius, results); + m_smallGrid.findInRange(pob, center_w, radius, results); +} + + +template +inline void DoubleSphereGrid::findInRange(Object const *pob, Vector const ¢er_w, float radius, SpatialSubdivisionFilter const &filter, std::set & results) +{ + m_largeGrid.findInRange(pob, center_w, radius, filter, results); + m_smallGrid.findInRange(pob, center_w, radius, filter, results); +} + + + + +#endif // _INCLUDED_SphereGrid_H + + + + diff --git a/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.cpp b/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.cpp new file mode 100644 index 00000000..1069c872 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.cpp @@ -0,0 +1,83 @@ +// ====================================================================== +// +// CustomizationDataProperty.cpp +// Copyright 2002 Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/CustomizationDataProperty.h" + +#include "sharedObject/CustomizationData.h" + +// ====================================================================== + +PropertyId CustomizationDataProperty::getClassPropertyId() +{ + return PROPERTY_HASH(CustomizationData, 0xDE36CB96); +} + +// ---------------------------------------------------------------------- +/** + * Construct a CustomizationDataProperty. + * + * @param owner the Object instance owning this new property. + */ + +CustomizationDataProperty::CustomizationDataProperty(Object &owner) : + Property(getClassPropertyId(), owner), + m_customizationData(new CustomizationData(owner)) +{ + //-- fetch local reference + m_customizationData->fetch(); +} + +// ---------------------------------------------------------------------- +/** + * Destroy the CustomizationDataProperty instance. + */ + +CustomizationDataProperty::~CustomizationDataProperty() +{ + //lint -esym(1540, CustomizationDataProperty::m_customizationData) // not zero'ed or freed // it's okay, it's ref counted and released. + m_customizationData->release(); +} + +// ---------------------------------------------------------------------- +/** + * Fetch a pointer to const of this property's CustomizationData instance. + * + * This function bumps up the reference count on the CustomizationData + * instance for the caller. + * + * @return a pointer to const of this property's CustomizationData instance. + */ + +const CustomizationData *CustomizationDataProperty::fetchCustomizationData() const +{ + m_customizationData->fetch(); + return m_customizationData; +} + +// ---------------------------------------------------------------------- +/** + * Fetch a pointer to this property's CustomizationData instance. + * + * This function bumps up the reference count on the CustomizationData + * instance for the caller. + * + * @return a pointer to this property's CustomizationData instance. + */ + +CustomizationData *CustomizationDataProperty::fetchCustomizationData() +{ + m_customizationData->fetch(); + return m_customizationData; +} + +// ====================================================================== + + + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.h b/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.h new file mode 100644 index 00000000..32212527 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/CustomizationDataProperty.h @@ -0,0 +1,50 @@ +// ====================================================================== +// +// CustomizationDataProperty.h +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_CustomizationDataProperty_H +#define INCLUDED_CustomizationDataProperty_H + +// ====================================================================== + +#include "sharedObject/Property.h" + +class CustomizationData; +class Object; + +// ====================================================================== + +class CustomizationDataProperty: public Property +{ +public: + + static PropertyId getClassPropertyId(); + +public: + + explicit CustomizationDataProperty(Object &owner); + virtual ~CustomizationDataProperty(); + + const CustomizationData *fetchCustomizationData() const; + CustomizationData *fetchCustomizationData(); + +private: + + // disabled + CustomizationDataProperty(); + CustomizationDataProperty(const CustomizationDataProperty&); + CustomizationDataProperty &operator =(const CustomizationDataProperty&); + +private: + + CustomizationData *const m_customizationData; + +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/property/LayerProperty.cpp b/engine/shared/library/sharedObject/src/shared/property/LayerProperty.cpp new file mode 100644 index 00000000..000de93a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/LayerProperty.cpp @@ -0,0 +1,51 @@ +// ====================================================================== +// +// LayerProperty.cpp +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/LayerProperty.h" + + +// ====================================================================== + +PropertyId LayerProperty::getClassPropertyId() +{ +// PropertyId id = LabelHash::hashLabel( "Property", "Layer" ); +// return id; + return PROPERTY_HASH(Layer, 0x78e8a2d2); +} + +// ====================================================================== + +LayerProperty::LayerProperty(Object& thisObject) : +Property(getClassPropertyId(), thisObject), +m_layer(NULL) +{ +} + +//------------------------------------------------------------------------- + +LayerProperty::~LayerProperty() +{ + if (m_layer != NULL) + { + delete m_layer; + m_layer = NULL; + } +} + +//------------------------------------------------------------------------- + +void LayerProperty::setLayer(TerrainGenerator::Layer* layer) +{ + if (m_layer != NULL) + delete m_layer; + + m_layer = layer; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/property/LayerProperty.h b/engine/shared/library/sharedObject/src/shared/property/LayerProperty.h new file mode 100644 index 00000000..00ff3f02 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/LayerProperty.h @@ -0,0 +1,54 @@ +// ====================================================================== +// +// LayerProperty.h +// Copyright 2001 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_LayerProperty_H +#define INCLUDED_LayerProperty_H + +// ====================================================================== + +#include "sharedObject/Property.h" +#include "sharedTerrain/TerrainGenerator.h" + + +// ====================================================================== + +class LayerProperty : public Property +{ +public: + + static PropertyId getClassPropertyId(); + +public: + LayerProperty(Object& thisObject); + ~LayerProperty(); + + TerrainGenerator::Layer * getLayer() const; + void setLayer(TerrainGenerator::Layer* layer); + +private: + TerrainGenerator::Layer * m_layer; + +private: + LayerProperty(); + LayerProperty(const LayerProperty&); + LayerProperty& operator= (const LayerProperty&); +}; + + +// ====================================================================== + +inline TerrainGenerator::Layer * LayerProperty::getLayer() const +{ + return m_layer; +} + +// ====================================================================== + + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/property/Property.cpp b/engine/shared/library/sharedObject/src/shared/property/Property.cpp new file mode 100644 index 00000000..9ecba208 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/Property.cpp @@ -0,0 +1,52 @@ +// ====================================================================== +// +// Property.cpp +// +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/Property.h" + +// ------------------------------------------------------------------------ + +Property::Property(PropertyId propertyId, Object& owner) +: + m_owner(owner), + m_propertyId(propertyId) +{ + DEBUG_FATAL(m_propertyId == 0, ("bad property value")); +} + +// ------------------------------------------------------------------------ + +Property::~Property() +{ +} + +// ------------------------------------------------------------------------ + +void Property::initializeFirstTimeObject() +{ +} + +// ------------------------------------------------------------------------ + +void Property::addToWorld() +{ +} + +// ------------------------------------------------------------------------ + +void Property::removeFromWorld() +{ +} + +// ------------------------------------------------------------------------ + +void Property::conclude() +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/property/Property.h b/engine/shared/library/sharedObject/src/shared/property/Property.h new file mode 100644 index 00000000..c842d2bb --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/Property.h @@ -0,0 +1,80 @@ +// ====================================================================== +// +// Property.h +// +// Copyright 2001-2002 Sony Online Entertainment +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_Property_H +#define INCLUDED_Property_H + +// ====================================================================== + +class Object; + +#include "sharedObject/PropertyId.h" + +// ====================================================================== + +#define PROPERTY_HASH( label, value ) LABEL_HASH( Property, label, value ) + +// ====================================================================== + +class Property +{ +protected: + + Property(PropertyId propertyId, Object& owner); + +public: + virtual ~Property() = 0; + + Object& getOwner(); + const Object& getOwner() const; + const PropertyId getPropertyId() const; + + virtual void initializeFirstTimeObject(); + + virtual void addToWorld(); + virtual void removeFromWorld(); + + virtual void conclude(); + + +private: + Object& m_owner; + const PropertyId m_propertyId; + + Property(); + Property(const Property&); + Property& operator= (const Property&); +}; + +// ------------------------------------------------------------------------ + +inline Object& Property::getOwner() +{ + return m_owner; +} + +// ------------------------------------------------------------------------ + +inline const Object& Property::getOwner() const +{ + return m_owner; +} + +// ------------------------------------------------------------------------ + +inline const PropertyId Property::getPropertyId() const +{ + return m_propertyId; +} + +// ------------------------------------------------------------------------ + + +#endif + diff --git a/engine/shared/library/sharedObject/src/shared/property/PropertyId.h b/engine/shared/library/sharedObject/src/shared/property/PropertyId.h new file mode 100644 index 00000000..1cb2f4e0 --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/property/PropertyId.h @@ -0,0 +1,19 @@ +// ====================================================================== +// +// PropertyId.h +// Copyright 2002, Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#ifndef INCLUDED_PropertyId_H +#define INCLUDED_PropertyId_H + +// ====================================================================== + +#include "sharedFoundation/LabelHash.h" +typedef LabelHash::Id PropertyId; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/shared/world/World.cpp b/engine/shared/library/sharedObject/src/shared/world/World.cpp new file mode 100644 index 00000000..e0d90fae --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/world/World.cpp @@ -0,0 +1,578 @@ +// ====================================================================== +// +// World.cpp +// asommers 2-26-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h" +#include "sharedObject/World.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedMessageDispatch/Emitter.h" +#include "sharedMessageDispatch/Message.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/ConfigSharedObject.h" +#include "sharedObject/LotManager.h" +#include "sharedObject/Object.h" +#include "sharedObject/ObjectList.h" +#include "sharedTerrain/TerrainObject.h" + +#include +#include + +// ====================================================================== +// World::Emitter +// ====================================================================== + +struct World::Emitter : public MessageDispatch::Emitter +{ +public: + + typedef MessageDispatch::Message > ObjectMessage; //lint -esym(754, Emitter::ObjectMessage) // (Info -- local structure member 'Emitter::ObjectMessage' not referenced) // It is referenced, Lint is incorrect. + ~Emitter (); +}; + +// ---------------------------------------------------------------------- + +World::Emitter::~Emitter () +{ +} + +// ====================================================================== +// WorldNamespace +// ====================================================================== + +namespace WorldNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + bool ms_installed; + int ms_frameNumber; + +#ifdef _DEBUG + bool ms_debugReport; + const char* const cms_objectListNames [WOL_Count] = + { + " WOL_Tangible", + "WOL_TangNotTargetable", + " WOL_Intangible", + " WOL_TangibleFlora", + " WOL_Inactive" + }; + + bool ms_logUninitializedObjects = false; + +#endif + + ObjectList* ms_objectList [WOL_Count]; + ObjectList* ms_queuedObjectList; + LotManager* ms_lotManager; + + World::Emitter ms_emitter; + + bool ms_valid = false; + + typedef std::set ObjectSet; + ObjectSet ms_objectSet; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace WorldNamespace; + +// ====================================================================== +// PUBLIC STATIC World +// ====================================================================== + +const char* const World::Messages::OBJECT_ADDED = "World::ObjectAdded"; +const char* const World::Messages::OBJECT_REMOVED = "World::ObjectRemoved"; +const char* const World::Messages::OBJECT_REMOVING = "World::ObjectRemoving"; +const char* const World::Messages::OBJECT_ADDED_PTR = "World::ObjectAddedPtr"; + +// ====================================================================== + +int World::getFrameNumber () +{ + return ms_frameNumber; +} + +// ---------------------------------------------------------------------- + +const LotManager* World::getConstLotManager () +{ + return ms_lotManager; +} + +// ---------------------------------------------------------------------- + +LotManager* World::getLotManager () +{ + return ms_lotManager; +} + +// ---------------------------------------------------------------------- + +void World::snapAllObjectsToTerrain () +{ + int i; + for (i = static_cast(WOL_MarkerObjectsStart); i < static_cast(WOL_MarkerObjectsEnd); ++i) + snapObjectsToTerrain (i); +} + +// ---------------------------------------------------------------------- + +void World::snapObjectsToTerrain (const int listIndex) +{ + int i; + for (i = 0; i < getNumberOfObjects (listIndex); i++) + snapObjectToTerrain (getObject (listIndex, i)); +} + +// ---------------------------------------------------------------------- + +void World::snapObjectToTerrain (Object* object, bool alignToTerrain) +{ + if (!TerrainObject::getInstance ()) + return; + + NOT_NULL (object); + + if (!object->getObjectTemplate ()) + IGNORE_RETURN(TerrainObject::getInstance ()->placeObject (*object, alignToTerrain)); + else + { + SharedObjectTemplate const * const sharedObjectTemplate = object->getObjectTemplate() ? object->getObjectTemplate()->asSharedObjectTemplate() : 0; + if (sharedObjectTemplate && sharedObjectTemplate->getSnapToTerrain ()) + IGNORE_RETURN(TerrainObject::getInstance ()->placeObject (*object, alignToTerrain, true)); + } +} + +// ====================================================================== +// PROTECTED STATIC World +// ====================================================================== + +void World::install () +{ + DEBUG_FATAL (ms_installed, ("World::install - already installed")); + ms_installed = true; + + //-- create the object lists + int i; + for (i = 0; i < static_cast(WOL_Count); i++) + ms_objectList [i] = new ObjectList (100); + + ms_queuedObjectList = new ObjectList (100); + +#ifdef _DEBUG + DebugFlags::registerFlag (ms_debugReport, "SharedObject", "reportWorld", debugReport); + DebugFlags::registerFlag (ms_logUninitializedObjects, "SharedObject", "logWorldUninitializedObjects"); +#endif + + ms_lotManager = new LotManager (16384.f, 8.f); + + ms_frameNumber = 0; + + //-- tell the appearance template list we allow timed templates + AppearanceTemplateList::setAllowTimedTemplates (true); + + ms_valid = true; +} + +// ---------------------------------------------------------------------- + +bool World::isValid () +{ + return ms_valid; +} + +// ---------------------------------------------------------------------- + +bool World::isInstalled() +{ + return ms_installed; +} + +// ---------------------------------------------------------------------- + +void World::remove () +{ + DEBUG_FATAL (!ms_installed, ("World::install - not installed")); + + ms_valid = false; + + //-- tell the appearance template list we no longer allow timed templates (this will delete all exiting timed templates) + AppearanceTemplateList::setAllowTimedTemplates (false); + + //-- delete all objectLists + { + for (int i = 0; i < static_cast(WOL_Count); ++i) + { + ObjectList* const objectList = ms_objectList [i]; + + while (!objectList->isEmpty()) + { + int const lastObjectIndex = objectList->getNumberOfObjects() - 1; + Object *const object = objectList->getObject(lastObjectIndex); + objectList->removeObjectByIndex(object, lastObjectIndex); + + // do not delete contained objects, since their container will delete them + if (!object->getAttachedTo()) + delete object; + } + + delete ms_objectList [i]; + ms_objectList [i] = 0; + } + } + + //-- delete queuedObject list + { + while (!ms_queuedObjectList->isEmpty ()) + { + int const lastObjectIndex = ms_queuedObjectList->getNumberOfObjects() - 1; + Object *const object = ms_queuedObjectList->getObject(lastObjectIndex); + ms_queuedObjectList->removeObjectByIndex(object, lastObjectIndex); + + delete object; + } + + delete ms_queuedObjectList; + ms_queuedObjectList = 0; + } + + delete ms_lotManager; + ms_lotManager = 0; + +#ifdef _DEBUG + if (!ms_objectSet.empty()) + { + DEBUG_REPORT_LOG(true, ("World::remove: The object set should be empty. The following objects have leaked:\n")); + ObjectSet::const_iterator end = ms_objectSet.end(); + for (ObjectSet::const_iterator iter = ms_objectSet.begin(); iter != end; ++iter) + { + Object const * const object = *iter; + DEBUG_REPORT_LOG(true, ("- %s\n", object->getDebugInformation(true).c_str())); + } + } + + DebugFlags::unregisterFlag(ms_debugReport); + DebugFlags::unregisterFlag(ms_logUninitializedObjects); +#endif + + ms_installed = false; +} + +// ---------------------------------------------------------------------- + +void World::addObject (Object* object, int listIndex) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (object); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + DEBUG_FATAL (existsInList (object, listIndex), ("object already in list")); + DEBUG_FATAL (existsInWorld (object), ("object already in world")); + + ms_objectSet.insert(object); + ms_objectList [listIndex]->addObject (object); + + //-- notification of addition is guaranteed to occur AFTER the object is actually added + { + Emitter::ObjectMessage const msg(Messages::OBJECT_ADDED, std::make_pair(object->getNetworkId(), listIndex)); + ms_emitter.emitMessage(msg); + } + { + MessageDispatch::Message const msg(Messages::OBJECT_ADDED_PTR, object); + ms_emitter.emitMessage(msg); + } + + //-- Add the object to the AlterScheduler. This is the way that the system + // gives an object its first alter. + if (object->isInitialized()) + AlterScheduler::submitForAlter(*object); + else + DEBUG_REPORT_LOG(ms_logUninitializedObjects, ("World::addObject(): skipping AlterScheduler::submitForAlter() on uninitialized object:pointer=[%p],id=[%s],template=[%s].\n", object, object->getNetworkId().getValueString().c_str(), object->getObjectTemplateName())); +} + +// ---------------------------------------------------------------------- + +bool World::removeObject (const Object* object, int listIndex) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (object); + DEBUG_FATAL (!object, ("World::removeObject - object is null")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + + ms_objectSet.erase(object); + + bool result; + int index = 0; + if (ms_objectList [listIndex]->find (object, &index)) + { + const NetworkId id = object->getNetworkId(); + + { + Emitter::ObjectMessage const msg(Messages::OBJECT_REMOVING, std::make_pair(id, listIndex)); + ms_emitter.emitMessage(msg); + } + + ms_objectList [listIndex]->removeObjectByIndex (object, index); + + { + Emitter::ObjectMessage const msg(Messages::OBJECT_REMOVED, std::make_pair(id, listIndex)); + ms_emitter.emitMessage(msg); + } + + result = true; + } + else + result = false; + + //-- Let the alter scheduler know this object should no longer be altered as if in the world. + // WARNING: do not remove this line! When objects are transferred from the world into a container, + // this line prevents a double alter. The double alter would have come from those objects + // both (1) remaining in the alter scheduler from previously being added to the world and + // (2)then altered by the container. + if (Object::shouldObjectsAlterChildrenAndContents()) + IGNORE_RETURN(AlterScheduler::removeObject(*const_cast(object))); + + return result; +} + +// ---------------------------------------------------------------------- + +void World::queueObject (Object* object) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + DEBUG_FATAL (!object, ("World::queueObject - object is null")); + + ms_queuedObjectList->addObject (object); +} + +// ---------------------------------------------------------------------- + +int World::getNumberOfObjects (int listIndex) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + + return ms_objectList [listIndex]->getNumberOfObjects (); +} + +// ---------------------------------------------------------------------- + +const Object* World::getConstObject (int listIndex, int index) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, ms_objectList [listIndex]->getNumberOfObjects ()); + + return ms_objectList [listIndex]->getObject (index); +} + +// ---------------------------------------------------------------------- + +Object* World::getObject (int listIndex, int index) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, ms_objectList [listIndex]->getNumberOfObjects ()); + + return ms_objectList [listIndex]->getObject (index); +} + +// ---------------------------------------------------------------------- + +int World::getNumberOfQueuedObjects () +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + + return ms_queuedObjectList->getNumberOfObjects (); +} + +// ---------------------------------------------------------------------- + +Object* World::getQueuedObject (const int index) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + + return ms_queuedObjectList->getObject (index); +} + +// ---------------------------------------------------------------------- + +const Object* World::getConstQueuedObject (const int index) +{ + return getQueuedObject (index); +} + +// ---------------------------------------------------------------------- + +const Object* World::findNextObject (const Object* object, int listIndex) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + + //-- if there are no objects, return 0 + if (!ms_objectList [listIndex]->getNumberOfObjects ()) + return 0; + + //-- if object is 0, return the first object (we are guaranteed at this point that the list has objects) + if (!object) + return ms_objectList [listIndex]->getObject (0); + + //-- search for object in list + int i; + for (i = 0; i < ms_objectList [listIndex]->getNumberOfObjects (); i++) + if (ms_objectList [listIndex]->getObject (i) == object) + break; + + //-- if object was not found in the list, return the first object + if (i == ms_objectList [listIndex]->getNumberOfObjects ()) + return ms_objectList [listIndex]->getObject (0); + + //-- return the next object + i = (i + 1) % ms_objectList [listIndex]->getNumberOfObjects (); + return ms_objectList [listIndex]->getObject (i); +} + +// ---------------------------------------------------------------------- + +int World::findObjectList(Object const * const object) +{ + int listIndex = WOL_MarkerAllObjectListsStart; + while (listIndex < WOL_MarkerAllObjectListsEnd) + { + if (existsInList(object, listIndex)) + break; + + ++listIndex; + } + + return listIndex; +} + +// ---------------------------------------------------------------------- + +Object* World::findClosestObjectTo (const Object* object, int listIndex) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, listIndex, static_cast(WOL_Count)); + + NOT_NULL (object); + + Object* closestObject = 0; + float shortestDistance = REAL_MAX; + + int i; + for (i = 0; i < ms_objectList [listIndex]->getNumberOfObjects (); i++) + { + if (object != ms_objectList [listIndex]->getObject (i)) + { + Object* const objectToCheck = ms_objectList [listIndex]->getObject (i); + const Vector position1 = object->getAppearance () ? object->getAppearanceSphereCenter_w () : object->getPosition_w (); + const Vector position2 = objectToCheck->getAppearance () ? objectToCheck->getAppearanceSphereCenter_w () : objectToCheck->getPosition_w (); + const float magnitudeBetweenSquared = position1.magnitudeBetweenSquared (position2); + + if (magnitudeBetweenSquared < shortestDistance) + { + shortestDistance = magnitudeBetweenSquared; + closestObject = objectToCheck; + } + } + } + + return closestObject; +} + +// ---------------------------------------------------------------------- + +const Object* World::findClosestConstObjectTo (const Object* object, int listIndex) +{ + return findClosestObjectTo (object, listIndex); +} + +// ---------------------------------------------------------------------- + +void World::validate () +{ + for (int i = 0; i < static_cast (WOL_Count); ++i) + { + for (int j = 0; j < getNumberOfObjects (i); ++j) + { + const Object* const object = getObject (i, j); + + if (!object->isInWorld ()) + DEBUG_FATAL (true, ("World::validate - object [%s] in world object list %i wasn't in the world", object->getNetworkId ().getValueString ().c_str (), i)); + } + } +} + +// ---------------------------------------------------------------------- + +void World::beginFrame () +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + + if (ConfigSharedObject::getValidateWorld ()) + validate(); + + //-- add any queued objects to the world + { + for (int i = 0; i < ms_queuedObjectList->getNumberOfObjects (); ++i) + ms_queuedObjectList->getObject (i)->addToWorld(); + + ms_queuedObjectList->removeAll (); + } +} + +// ---------------------------------------------------------------------- + +void World::endFrame () +{ + ++ms_frameNumber; +} + +// ---------------------------------------------------------------------- + +const MessageDispatch::Emitter& World::getEmitter () +{ + DEBUG_FATAL (!ms_installed, ("not installed\n")); + return ms_emitter; +} + +// ---------------------------------------------------------------------- + +bool World::existsInList (const Object* object, int listIndex) +{ + int index; + return ms_objectList [listIndex]->find (object, &index); +} + +// ---------------------------------------------------------------------- + +bool World::existsInWorld (const Object* object) +{ + return ms_objectSet.find(object) != ms_objectSet.end(); +} + +// ====================================================================== +// PRIVATE STATIC World +// ====================================================================== + +void World::debugReport () +{ + if (!ms_installed) + return; + + DEBUG_REPORT_PRINT (true, ("-- World\n")); + for (int i = 0; i < static_cast (WOL_Count); i++) + DEBUG_REPORT_PRINT (true, ("[%s] %4i objects\n", cms_objectListNames [i], World::getNumberOfObjects (i))); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedObject/src/shared/world/World.h b/engine/shared/library/sharedObject/src/shared/world/World.h new file mode 100644 index 00000000..bbfa613a --- /dev/null +++ b/engine/shared/library/sharedObject/src/shared/world/World.h @@ -0,0 +1,135 @@ +// ====================================================================== +// +// World.h +// asommers 2-26-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_World_H +#define INCLUDED_World_H + +// ====================================================================== + +enum WorldObjectLists +{ + WOL_MarkerAllObjectListsStart, + WOL_MarkerRenderedStart = WOL_MarkerAllObjectListsStart, + + WOL_MarkerObjectsStart = WOL_MarkerRenderedStart, + + WOL_Tangible = WOL_MarkerObjectsStart, + WOL_TangibleNotTargetable, + WOL_Intangible, + WOL_TangibleFlora, + + WOL_MarkerObjectsEnd, + WOL_MarkerRenderedEnd = WOL_MarkerObjectsEnd, + + WOL_Inactive = WOL_MarkerObjectsEnd, + + WOL_Count, + WOL_MarkerAllObjectListsEnd = WOL_Count +}; + +// ====================================================================== + +class LotManager; +class Object; +class ObjectList; +class NetworkId; + +namespace MessageDispatch +{ + class Emitter; +} + +// ====================================================================== + +class World +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct Messages + { + public: + + static const char * const OBJECT_ADDED; + static const char * const OBJECT_REMOVING; + static const char * const OBJECT_REMOVED; + static const char * const OBJECT_ADDED_PTR; + + // message type contains a std::pair + // second parameter is the index which was operated upon + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct Emitter; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + + static int getFrameNumber (); + + static const LotManager* getConstLotManager (); + static LotManager* getLotManager (); + + static void snapAllObjectsToTerrain (); + static void snapObjectsToTerrain (int listIndex); + static void snapObjectToTerrain (Object* object, bool alignToTerrain=false); + + static void validate (); + static bool isValid (); + + static bool existsInWorld (const Object* object); + static bool isInstalled(); + + static int getNumberOfObjects (int listIndex); + static Object* getObject (int listIndex, int index); + static const Object* getConstObject (int listIndex, int index); + +protected: + + static void addObject (Object* object, int listIndex); + static bool removeObject (const Object* object, int listIndex); + static void queueObject (Object* object); + + static Object* findClosestObjectTo (const Object* object, int listIndex); + static const Object* findClosestConstObjectTo (const Object* object, int listIndex); + + static const Object* findNextObject (const Object* object, int listIndex); + + static int findObjectList(Object const * object); + + static const MessageDispatch::Emitter& getEmitter (); + + static int getNumberOfQueuedObjects (); + static Object* getQueuedObject (int index); + static const Object* getConstQueuedObject (int index); + static bool existsInList (const Object* object, int listIndex); + + static void install (); + static void remove (); + + static void beginFrame (); + static void endFrame (); + + static void debugReport (); + +private: + + World (); + virtual ~World (); + World (const World&); + World& operator= (const World&); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedObject/src/win32/FirstSharedObject.cpp b/engine/shared/library/sharedObject/src/win32/FirstSharedObject.cpp new file mode 100644 index 00000000..4221af2e --- /dev/null +++ b/engine/shared/library/sharedObject/src/win32/FirstSharedObject.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstObject.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedObject/FirstSharedObject.h"