Olympe Engine 2.0
2D Game Engine with ECS Architecture
Loading...
Searching...
No Matches
PrefabFactory.cpp
Go to the documentation of this file.
1/*
2 Olympe Engine V2 - 2025
3 Nicolas Chereau
4 nchereau@gmail.com
5
6 Purpose:
7 - Implementation file for PrefabFactory class.
8 - Component-agnostic instantiation system.
9*/
10
11#include "prefabfactory.h"
12#include "ComponentRegistry.h"
13#include "ComponentDefinition.h"
14#include "PrefabScanner.h"
15#include "ParameterResolver.h"
16#include "World.h"
17#include "DataManager.h"
18#include "ECS_Components.h"
19#include "ECS_Components_AI.h"
21#include "system/system_utils.h"
22#include "AI/BehaviorTree.h"
23#include <string>
24#include <unordered_map>
25#include "VideoGame.h"
26
27// ========================================================================
28// Component Factory Registry Implementation
29// ========================================================================
30
31void PrefabFactory::RegisterComponentFactory(const std::string& componentName,
32 std::function<bool(EntityID, const ComponentDefinition&)> factory)
33{
34 // Check if component is already registered (prevents duplicate registrations from multiple translation units)
35 if (m_componentFactories.find(componentName) != m_componentFactories.end())
36 {
37 // Already registered, silently ignore duplicate
38 return;
39 }
40
41 // First registration: store factory and log
42 m_componentFactories[componentName] = factory;
43 std::cout << "[ComponentRegistry] Registered: " << componentName << "\n";
44}
45
46bool PrefabFactory::IsComponentRegistered(const std::string& componentName) const
47{
48 return m_componentFactories.find(componentName) != m_componentFactories.end();
49}
50
51std::vector<std::string> PrefabFactory::GetRegisteredComponents() const
52{
53 std::vector<std::string> components;
54 components.reserve(m_componentFactories.size());
55 for (const auto& kv : m_componentFactories)
56 {
57 components.push_back(kv.first);
58 }
59 return components;
60}
61
62// Helper function for macro
63void RegisterComponentFactory_Internal(const char* componentName,
64 std::function<bool(EntityID, const ComponentDefinition&)> factory)
65{
67}
68
69// ========================================================================
70// Public API Implementation
71// ========================================================================
72
74{
76 {
77 SYSTEM_LOG << "PrefabFactory::PreloadAllPrefabs: Already preloaded\n";
78 return;
79 }
80
81 SYSTEM_LOG << "+===========================================================+\n";
82 SYSTEM_LOG << "| PREFAB FACTORY: PRELOADING ALL PREFABS |\n";
83 SYSTEM_LOG << "+===========================================================+\n";
84
85 // Use new unified Initialize method from PrefabScanner
88
89 // Store scanner for type normalization
90 m_scanner = std::make_unique<PrefabScanner>(std::move(scanner));
91
92 int prefabCount = static_cast<int>(m_prefabRegistry.GetCount());
93
94 SYSTEM_LOG << "ok - Loaded " << prefabCount << " prefabs:\n";
95
97 for (const auto& name : allNames)
98 {
100 if (bp && bp->isValid)
101 {
102 SYSTEM_LOG << " +- " << name << " (" << bp->components.size() << " components)\n";
103 }
104 }
105
106 SYSTEM_LOG << "\nok - PrefabFactory ready\n\n";
107 m_prefabsPreloaded = true;
108}
109
111{
113 {
114 SYSTEM_LOG << "/!\\ PrefabFactory: Prefabs not preloaded! Call PreloadAllPrefabs() first\n";
115 return INVALID_ENTITY_ID;
116 }
117
118 const PrefabBlueprint* blueprint = m_prefabRegistry.Find(prefabName);
119
120 if (!blueprint || !blueprint->isValid)
121 {
122 SYSTEM_LOG << "x PrefabFactory: Prefab '" << prefabName << "' not found\n";
123 return INVALID_ENTITY_ID;
124 }
125
127}
128
129EntityID PrefabFactory::CreateEntity(const std::string& prefabName)
130{
131 // Try legacy system first
132 if (m_prefabs.find(prefabName) != m_prefabs.end())
133 {
135 m_prefabs[prefabName](newEntity);
136 SYSTEM_LOG << "PrefabFactory::CreateEntity '" << prefabName << "' created (ID: " << newEntity << ")\n";
137 return newEntity;
138 }
139
140 // Fallback to modern system
141 return CreateEntityFromPrefabName(prefabName);
142}
143
145{
147 SYSTEM_LOG << "PrefabFactory: Registry cached with " << registry.GetCount() << " prefabs\n";
148
149 // Mark as preloaded if registry is non-empty
150 if (registry.GetCount() > 0)
151 {
152 m_prefabsPreloaded = true;
153 }
154}
155
156std::string PrefabFactory::NormalizeType(const std::string& type) const
157{
158 if (m_scanner)
159 {
160 return m_scanner->NormalizeType(type);
161 }
162 return type;
163}
164
165bool PrefabFactory::AreTypesEquivalent(const std::string& type1, const std::string& type2) const
166{
167 if (m_scanner)
168 {
169 return m_scanner->AreTypesEquivalent(type1, type2);
170 }
171 return type1 == type2;
172}
173
174bool PrefabFactory::IsTypeRegistered(const std::string& type) const
175{
176 if (m_scanner)
177 {
178 return m_scanner->IsTypeRegistered(type);
179 }
180 return false;
181}
182
183bool PrefabFactory::GetCanonicalInfo(const std::string& type, std::string& outCanonical,
184 std::string& outPrefabFile) const
185{
186 if (m_scanner)
187 {
188 return m_scanner->GetCanonicalInfo(type, outCanonical, outPrefabFile);
189 }
190 return false;
191}
192
194{
195 if (!blueprint.isValid)
196 {
197 SYSTEM_LOG << "PrefabFactory::CreateEntityFromBlueprint: Invalid blueprint '"
198 << blueprint.prefabName << "'\n";
199 return INVALID_ENTITY_ID;
200 }
201
202 // Create entity
203 World& world = World::Get();
204 EntityID entity = world.CreateEntity();
205
206 if (entity == INVALID_ENTITY_ID)
207 {
208 SYSTEM_LOG << "PrefabFactory::CreateEntityFromBlueprint: Failed to create entity for '"
209 << blueprint.prefabName << "'\n";
210 return INVALID_ENTITY_ID;
211 }
212
213 // Instantiate all components
214 int successCount = 0;
215 int failCount = 0;
216
217 for (const auto& componentDef : blueprint.components)
218 {
220 {
221 successCount++;
222 }
223 else
224 {
225 failCount++;
226 SYSTEM_LOG << "PrefabFactory::CreateEntityFromBlueprint: Failed to instantiate component '"
227 << componentDef.componentType << "' on entity " << entity << "\n";
228 }
229 }
230
231 // -> Auto-assign render layer based on entity type (if requested)
232 if (autoAssignLayer &&
233 world.HasComponent<Identity_data>(entity) &&
234 world.HasComponent<Position_data>(entity))
235 {
236 const Identity_data& identity = world.GetComponent<Identity_data>(entity);
238 world.SetEntityLayer(entity, defaultLayer);
239
240 }
241
242 // --- Attacher le BehaviorTree si référencé via AIBehavior_data ---
243 std::string btPath = "";
244 if (world.HasComponent<AIBehavior_data>(entity))
245 {
246 btPath = world.GetComponent<AIBehavior_data>(entity).behaviorTreePath;
247 }
248
249 // Charger et enregistrer l'arbre si un chemin valide est trouvé
250 if (!btPath.empty())
251 {
252 // Load tree via BehaviorTreeManager
254
255 if (treeId == 0) // Not already loaded, try to load
256 {
257 // Generate temporary ID for this tree
258 static uint32_t nextTempTreeId = 1000;
259 treeId = nextTempTreeId++;
260
261 if (BehaviorTreeManager::Get().LoadTreeFromFile(btPath, treeId))
262 {
263 SYSTEM_LOG << "[PrefabFactory::CreateEntityFromBlueprint] Loaded BehaviorTree: " << btPath << " (ID=" << treeId << ")\n";
264 }
265 else
266 {
267 SYSTEM_LOG << "[PrefabFactory::CreateEntityFromBlueprint] WARNING: BT not found or invalid: " << btPath << "\n";
268 treeId = 0;
269 }
270 }
271
272 // Create BehaviorTreeRuntime_data if tree loaded successfully
273 if (treeId > 0)
274 {
276 btRuntime.AITreePath = btPath;
278
279 if (world.HasComponent<AIBehavior_data>(entity))
280 world.GetComponent<AIBehavior_data>(entity).isActive = true;
281 }
282 }
283
284 return entity;
285}
286
290 bool autoAssignLayer)
291{
292 if (!blueprint.isValid)
293 {
294 SYSTEM_LOG << "PrefabFactory::CreateEntityWithOverrides: Invalid blueprint '"
295 << blueprint.prefabName << "'\n";
296 return INVALID_ENTITY_ID;
297 }
298
299 // Create entity
300 World& world = World::Get();
301 EntityID entity = world.CreateEntity();
302
303 if (entity == INVALID_ENTITY_ID)
304 {
305 SYSTEM_LOG << "PrefabFactory::CreateEntityWithOverrides: Failed to create entity for '"
306 << blueprint.prefabName << "'\n";
307 return INVALID_ENTITY_ID;
308 }
309
310 // Use ParameterResolver to merge prefab defaults with instance parameters
312 std::vector<ResolvedComponentInstance> resolvedComponents = resolver.Resolve(blueprint, instanceParams);
313
314 // Instantiate components with resolved parameters
315 // NOTE: If some components fail to instantiate, the entity is still returned with partial state.
316 // This is intentional - allows entities to be created even if some optional components fail.
317 // Callers should check component existence before accessing them.
318 int successCount = 0;
319 int failCount = 0;
320
321 for (const auto& resolved : resolvedComponents)
322 {
323 if (!resolved.isValid)
324 {
325 failCount++;
326 SYSTEM_LOG << " /!\\ Invalid resolved component: " << resolved.componentType << "\n";
327 continue;
328 }
329
331 compDef.componentType = resolved.componentType;
332 compDef.parameters = resolved.parameters;
333
334 if (InstantiateComponent(entity, compDef))
335 {
336 successCount++;
337 }
338 else
339 {
340 failCount++;
341 SYSTEM_LOG << " /!\\ Failed to instantiate component: " << resolved.componentType << "\n";
342 }
343 }
344
345 // Override position INCLUDING z component (zOrder) to preserve layer depth
346 if (world.HasComponent<Position_data>(entity))
347 {
348 auto& pos = world.GetComponent<Position_data>(entity);
349 pos.position = instanceParams.position;
350 }
351
352 // -> Auto-assign render layer based on entity type (if requested)
353 if (autoAssignLayer &&
354 world.HasComponent<Identity_data>(entity) &&
355 world.HasComponent<Position_data>(entity))
356 {
357 const Identity_data& identity = world.GetComponent<Identity_data>(entity);
359 world.SetEntityLayer(entity, defaultLayer);
360 }
361
362 // --- Attacher le BehaviorTree si référencé via AIBehavior_data ---
363 std::string btPath = "";
364 if (world.HasComponent<AIBehavior_data>(entity))
365 {
366 btPath = world.GetComponent<AIBehavior_data>(entity).behaviorTreePath;
367 }
368
369 // Charger et enregistrer l'arbre si un chemin valide est trouvé
370 if (!btPath.empty())
371 {
372 // Load tree via BehaviorTreeManager
374
375 if (treeId == 0) // Not already loaded, try to load
376 {
377 // Generate temporary ID for this tree
378 static uint32_t nextTempTreeId = 1000;
379 treeId = nextTempTreeId++;
380
381 if (BehaviorTreeManager::Get().LoadTreeFromFile(btPath, treeId))
382 {
383 SYSTEM_LOG << "[PrefabFactory::CreateEntityWithOverrides] Loaded BehaviorTree: " << btPath << " (ID=" << treeId << ")\n";
384 }
385 else
386 {
387 SYSTEM_LOG << "[PrefabFactory::CreateEntityWithOverrides] WARNING: BT not found or invalid: " << btPath << "\n";
388 treeId = 0;
389 }
390 }
391
392 // Create BehaviorTreeRuntime_data if tree loaded successfully
393 if (treeId > 0)
394 {
396 btRuntime.AITreePath = btPath;
398
399 if (world.HasComponent<AIBehavior_data>(entity))
400 world.GetComponent<AIBehavior_data>(entity).isActive = true;
401 }
402 }
403
404 SYSTEM_LOG << " -> Created with " << successCount << " components";
405 if (failCount > 0)
406 {
407 SYSTEM_LOG << " (" << failCount << " failed)";
408 }
409 SYSTEM_LOG << "\n";
410
411 return entity;
412}
413
415{
416 const std::string& type = componentDef.componentType;
417
418 // Step 1: Try auto-registered components first
419 auto it = m_componentFactories.find(type);
420 if (it != m_componentFactories.end())
421 {
422 // Call the registered factory function to create component
423 bool success = it->second(entity, componentDef);
424 if (!success)
425 {
426 return false;
427 }
428
429 // For components that need specialized parameter handling, call the specialized function
430 // Note: The specialized function applies parameters but does NOT recreate the component
431 // This if-else chain is intentional for clarity and ease of modification.
432 // Performance impact is negligible as this only runs once per component during entity creation.
433 if (type == "BehaviorTreeRuntime_data")
435 else if (type == "Position_data")
436 return InstantiatePosition(entity, componentDef);
437 else if (type == "Identity_data")
438 return InstantiateIdentity(entity, componentDef);
439 else if (type == "PhysicsBody_data")
440 return InstantiatePhysicsBody(entity, componentDef);
441 else if (type == "VisualSprite_data")
443 else if (type == "VisualAnimation_data")
445 else if (type == "AIBlackboard_data")
447 else if (type == "AISenses_data")
448 return InstantiateAISenses(entity, componentDef);
449 else if (type == "MoveIntent_data")
450 return InstantiateMoveIntent(entity, componentDef);
451 else if (type == "NavigationAgent_data")
453
454 // Component created successfully with default values
455 // too soon return true;
456 }
457
458 // Step 2: Fallback to legacy specialized functions (for backward compatibility)
459 // This allows the system to work even if AUTO_REGISTER_COMPONENT was forgotten
460 if (type == "Identity" || type == "Identity_data")
461 return InstantiateIdentity(entity, componentDef);
462 else if (type == "Position" || type == "Position_data")
463 return InstantiatePosition(entity, componentDef);
464 else if (type == "PhysicsBody" || type == "PhysicsBody_data")
465 return InstantiatePhysicsBody(entity, componentDef);
466 else if (type == "VisualSprite" || type == "VisualSprite_data")
468 else if (type == "VisualAnimation" || type == "VisualAnimation_data")
470 else if (type == "VisualEditor" || type == "VisualEditor_data")
472 else if (type == "AIBehavior" || type == "AIBehavior_data")
473 return InstantiateAIBehavior(entity, componentDef);
474 else if (type == "AIBlackboard" || type == "AIBlackboard_data")
476 else if (type == "AISenses" || type == "AISenses_data")
477 return InstantiateAISenses(entity, componentDef);
478 else if (type == "AIState" || type == "AIState_data")
479 return InstantiateAIState(entity, componentDef);
480 else if (type == "BehaviorTreeRuntime" || type == "BehaviorTreeRuntime_data")
482 else if (type == "MoveIntent" || type == "MoveIntent_data")
483 return InstantiateMoveIntent(entity, componentDef);
484 else if (type == "AttackIntent" || type == "AttackIntent_data")
486 else if (type == "BoundingBox" || type == "BoundingBox_data")
487 return InstantiateBoundingBox(entity, componentDef);
488 else if (type == "Movement" || type == "Movement_data")
489 return InstantiateMovement(entity, componentDef);
490 else if (type == "Health" || type == "Health_data")
491 return InstantiateHealth(entity, componentDef);
492 else if (type == "TriggerZone" || type == "TriggerZone_data")
493 return InstantiateTriggerZone(entity, componentDef);
494 else if (type == "CollisionZone" || type == "CollisionZone_data")
496 else if (type == "Animation" || type == "Animation_data")
497 return InstantiateAnimation(entity, componentDef);
498 else if (type == "FX" || type == "FX_data")
499 return InstantiateFX(entity, componentDef);
500 else if (type == "AudioSource" || type == "AudioSource_data")
501 return InstantiateAudioSource(entity, componentDef);
502 else if (type == "Controller" || type == "Controller_data")
503 return InstantiateController(entity, componentDef);
504 else if (type == "PlayerController" || type == "PlayerController_data")
506 else if (type == "PlayerBinding" || type == "PlayerBinding_data")
508 else if (type == "NPC" || type == "NPC_data")
509 return InstantiateNPC(entity, componentDef);
510 else if (type == "Inventory" || type == "Inventory_data")
511 return InstantiateInventory(entity, componentDef);
512 else if (type == "Camera" || type == "Camera_data")
513 return InstantiateCamera(entity, componentDef);
514 else if (type == "CameraTarget" || type == "CameraTarget_data")
516 else if (type == "CameraEffects" || type == "CameraEffects_data")
518 else if (type == "CameraBounds" || type == "CameraBounds_data")
520 else if (type == "CameraInputBinding" || type == "CameraInputBinding_data")
522 else if (type == "InputMapping" || type == "InputMapping_data")
524 else
525 {
526 SYSTEM_LOG << "PrefabFactory::InstantiateComponent: Unknown component type '"
527 << type << "'\n";
528 SYSTEM_LOG << " Available auto-registered components:\n";
529 for (const auto& kv : m_componentFactories)
530 {
531 SYSTEM_LOG << " - " << kv.first << "\n";
532 }
533 return false;
534 }
535
536}
537
538// ========================================================================
539// Component-specific instantiation helpers
540// ========================================================================
541
542// Helper function to convert string to EntityType enum
543static EntityType StringToEntityType(const std::string& typeStr)
544{
545 static const std::unordered_map<std::string, EntityType> typeMap = {
546 {"Player", EntityType::Player},
547 {"NPC", EntityType::NPC},
548 {"Enemy", EntityType::Enemy},
549 {"Item", EntityType::Item},
550 {"Collectible", EntityType::Collectible},
551 {"Effect", EntityType::Effect},
552 {"Particle", EntityType::Particle},
553 {"UIElement", EntityType::UIElement},
554 {"Background", EntityType::Background},
555 {"Trigger", EntityType::Trigger},
556 {"Waypoint", EntityType::Waypoint},
557 {"Static", EntityType::Static},
558 {"Dynamic", EntityType::Dynamic}
559 };
560
561 auto it = typeMap.find(typeStr);
562 return (it != typeMap.end()) ? it->second : EntityType::None;
563}
564
566{
567 // Get the EXISTING component created by auto-registration
569 {
570 std::cerr << "[PrefabFactory] ERROR: Identity_data not found for entity " << entity << std::endl;
571 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
572 return false;
573 }
574
575 // Get reference to existing component (not a copy)
577
578 // Extract parameters
579 if (def.HasParameter("name"))
580 identity.name = def.GetParameter("name")->AsString();
581
582 if (def.HasParameter("tag"))
583 identity.tag = def.GetParameter("tag")->AsString();
584
585 if (def.HasParameter("entityType"))
586 {
587 // Store string type for backward compatibility
588 identity.type = def.GetParameter("entityType")->AsString();
589
590 // Map string to EntityType enum using helper function
591 identity.entityType = StringToEntityType(identity.type);
592 }
593
594 // DO NOT call AddComponent() - component is already modified by reference
595 return true;
596}
597
599{
600 // Get the EXISTING component created by auto-registration
602 {
603 std::cerr << "[PrefabFactory] ERROR: Position_data not found for entity " << entity << std::endl;
604 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
605 return false;
606 }
607
608 // Get reference to existing component (not a copy)
609 Position_data& position = World::Get().GetComponent<Position_data>(entity);
610
611 // Extract position vector
612 if (def.HasParameter("position"))
613 {
614 position.position = def.GetParameter("position")->AsVector();
615 }
616 else if (def.HasParameter("x") && def.HasParameter("y"))
617 {
618 float x = def.GetParameter("x")->AsFloat();
619 float y = def.GetParameter("y")->AsFloat();
620 float z = def.HasParameter("z") ? def.GetParameter("z")->AsFloat() : 0.0f;
621 position.position = Vector(x, y, z);
622 }
623
624 // DO NOT call AddComponent() - component is already modified by reference
625 return true;
626}
627
629{
630 // Get the EXISTING component created by auto-registration
632 {
633 std::cerr << "[PrefabFactory] ERROR: PhysicsBody_data not found for entity " << entity << std::endl;
634 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
635 return false;
636 }
637
638 // Get reference to existing component (not a copy)
640
641 // Extract parameters
642 if (def.HasParameter("mass"))
643 physics.mass = def.GetParameter("mass")->AsFloat();
644
645 if (def.HasParameter("speed"))
646 physics.speed = def.GetParameter("speed")->AsFloat();
647
648 // REQUIREMENT E: Apply friction, useGravity, and rotation when present
649 if (def.HasParameter("friction"))
650 physics.friction = def.GetParameter("friction")->AsFloat();
651
652 if (def.HasParameter("useGravity"))
653 physics.useGravity = def.GetParameter("useGravity")->AsBool();
654
655 if (def.HasParameter("rotation"))
656 physics.rotation = def.GetParameter("rotation")->AsFloat();
657
658 // DO NOT call AddComponent() - component is already modified by reference
659 return true;
660}
661
663{
664 // Get the EXISTING component created by auto-registration
666 {
667 std::cerr << "[PrefabFactory] ERROR: VisualSprite_data not found for entity " << entity << std::endl;
668 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
669 return false;
670 }
671
672 // Get reference to existing component (not a copy)
674
675 // Extract sprite path and load sprite
676 if (def.HasParameter("spritePath"))
677 {
678 std::string spritePath = def.GetParameter("spritePath")->AsString();
679
680 // Load sprite via DataManager
681 visual.sprite = DataManager::Get().GetSprite(spritePath, spritePath, ResourceCategory::GameEntity);
682
683 if (!visual.sprite)
684 {
685 SYSTEM_LOG << "PrefabFactory::InstantiateVisualSprite: Failed to load sprite '"
686 << spritePath << "' - component will have null sprite\n";
687 // Don't fail completely - create component with null sprite
688 }
689 else
690 {
691 // Get texture dimensions for srcRect
692 float texW, texH;
694
695 // Extract optional srcRect
696 if (def.HasParameter("srcX") && def.HasParameter("srcY") &&
697 def.HasParameter("srcW") && def.HasParameter("srcH"))
698 {
699 visual.srcRect.x = def.GetParameter("srcX")->AsFloat();
700 visual.srcRect.y = def.GetParameter("srcY")->AsFloat();
701 visual.srcRect.w = def.GetParameter("srcW")->AsFloat();
702 visual.srcRect.h = def.GetParameter("srcH")->AsFloat();
703 }
704 else
705 {
706 // Default to full texture
707 visual.srcRect = SDL_FRect{0, 0, texW, texH};
708 }
709
710 // Extract optional hotSpot
711 if (def.HasParameter("hotSpot"))
712 {
713 visual.hotSpot = def.GetParameter("hotSpot")->AsVector();
714 }
715 else if (def.HasParameter("hotSpotX") && def.HasParameter("hotSpotY"))
716 {
717 float x = def.GetParameter("hotSpotX")->AsFloat();
718 float y = def.GetParameter("hotSpotY")->AsFloat();
719 visual.hotSpot = Vector(x, y, 0.0f);
720 }
721 else
722 {
723 // Default to center of sprite
724 visual.hotSpot = Vector(texW / 2.0f, texH / 2.0f, 0.0f);
725 }
726 }
727 }
728
729 // Extract optional color
730 if (def.HasParameter("color"))
731 {
732 visual.color = def.GetParameter("color")->AsColor();
733 }
734
735 // REQUIREMENT E: Apply visible parameter when explicitly provided
736 if (def.HasParameter("visible"))
737 {
738 visual.visible = def.GetParameter("visible")->AsBool();
739 }
740
741 // NOTE: width/height/layer fields don't exist in VisualSprite_data struct yet
742 // These parameters are validated by schema but not applied until struct is updated
743 // For now, srcRect.w and srcRect.h serve as the effective width/height
744
745 // DO NOT call AddComponent() - component is already modified by reference
746 return true;
747}
748
750{
752
753 // Extract sprite path and load sprite
754 if (def.HasParameter("spritePath"))
755 {
756 std::string spritePath = def.GetParameter("spritePath")->AsString();
757
758 // Load sprite via DataManager
759 editor.sprite = DataManager::Get().GetSprite(spritePath, spritePath, ResourceCategory::GameEntity);
760
761 if (!editor.sprite)
762 {
763 SYSTEM_LOG << "PrefabFactory::InstantiateVisualEditor: Failed to load sprite '"
764 << spritePath << "' - component will have null sprite\n";
765 // Don't fail completely - create component with null sprite
766 }
767 else
768 {
769 // Get texture dimensions for srcRect
770 float texW, texH;
772
773 // Set srcRect to full texture dimensions
774 editor.srcRect = SDL_FRect{0, 0, texW, texH};
775
776 // Set hotSpot to center of sprite
777 editor.hotSpot = Vector(texW / 2.0f, texH / 2.0f, 0.0f);
778 }
779 }
780
781 // Extract optional color
782 if (def.HasParameter("color"))
783 {
784 editor.color = def.GetParameter("color")->AsColor();
785 }
786 else
787 {
788 // Default to white
789 editor.color = SDL_Color{255, 255, 255, 255};
790 }
791
792 // Extract optional visibility flag
793 if (def.HasParameter("visible"))
794 {
795 editor.isVisible = def.GetParameter("visible")->AsBool();
796 }
797 else
798 {
799 // Default to visible
800 editor.isVisible = true;
801 }
802
803 // REQUIREMENT E: Apply layer when explicitly provided (if VisualEditor_data had the field)
804 // NOTE: width/height/layer fields don't exist in VisualEditor_data struct yet
805 // These parameters are validated by schema but not applied until struct is updated
806
808 return true;
809}
810
812{
813 // Get the EXISTING component created by auto-registration
815 {
816 std::cerr << "[PrefabFactory] ERROR: VisualAnimation_data not found for entity " << entity << std::endl;
817 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
818 return false;
819 }
820
821 // Get reference to existing component (not a copy)
823
824 // Extract animation bank reference
825 if (def.HasParameter("bankId"))
826 animData.bankId = def.GetParameter("bankId")->AsString();
827
828 // Extract current animation name
829 if (def.HasParameter("currentAnimName"))
830 animData.currentAnimName = def.GetParameter("currentAnimName")->AsString();
831
832 // Extract optional animation graph path
833 if (def.HasParameter("animGraphPath"))
834 animData.animGraphPath = def.GetParameter("animGraphPath")->AsString();
835
836 // Extract playback settings
837 if (def.HasParameter("playbackSpeed"))
838 animData.playbackSpeed = def.GetParameter("playbackSpeed")->AsFloat();
839
840 if (def.HasParameter("isPlaying"))
841 animData.isPlaying = def.GetParameter("isPlaying")->AsBool();
842
843 if (def.HasParameter("isPaused"))
844 animData.isPaused = def.GetParameter("isPaused")->AsBool();
845
846 if (def.HasParameter("loop"))
847 animData.loop = def.GetParameter("loop")->AsBool();
848
849 // Extract visual transforms
850 if (def.HasParameter("flipX"))
851 animData.flipX = def.GetParameter("flipX")->AsBool();
852
853 if (def.HasParameter("flipY"))
854 animData.flipY = def.GetParameter("flipY")->AsBool();
855
856 // DO NOT call AddComponent() - component is already modified by reference
857 return true;
858}
859
861{
863
864 // Extract behavior type
865 if (def.HasParameter("behaviorType"))
866 ai.behaviorType = def.GetParameter("behaviorType")->AsString();
867
869 return true;
870}
871
873{
874 // Get the EXISTING component created by auto-registration
876 {
877 std::cerr << "[PrefabFactory] ERROR: AIBlackboard_data not found for entity " << entity << std::endl;
878 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
879 return false;
880 }
881
882 // Get reference to existing component (not a copy)
884
885 // Extract blackboard parameters
886 if (def.HasParameter("targetEntity"))
887 blackboard.targetEntity = def.GetParameter("targetEntity")->AsEntityRef();
888
889 if (def.HasParameter("hasTarget"))
890 blackboard.hasTarget = def.GetParameter("hasTarget")->AsBool();
891
892 if (def.HasParameter("attackCooldown"))
893 blackboard.attackCooldown = def.GetParameter("attackCooldown")->AsFloat();
894
895 // Add support for additional AI parameters
896 if (def.HasParameter("distanceToTarget"))
897 blackboard.distanceToTarget = def.GetParameter("distanceToTarget")->AsFloat();
898
899 if (def.HasParameter("targetVisible"))
900 blackboard.targetVisible = def.GetParameter("targetVisible")->AsBool();
901
902 if (def.HasParameter("targetInRange"))
903 blackboard.targetInRange = def.GetParameter("targetInRange")->AsBool();
904
905 // DO NOT call AddComponent() - component is already modified by reference
906 return true;
907}
908
910{
911 // Get the EXISTING component created by auto-registration
913 {
914 std::cerr << "[PrefabFactory] ERROR: AISenses_data not found for entity " << entity << std::endl;
915 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
916 return false;
917 }
918
919 // Get reference to existing component (not a copy)
921
922 // Extract senses parameters
923 if (def.HasParameter("visionRadius"))
924 senses.visionRadius = def.GetParameter("visionRadius")->AsFloat();
925 else if (def.HasParameter("visionRange"))
926 senses.visionRadius = def.GetParameter("visionRange")->AsFloat();
927
928 if (def.HasParameter("visionAngle"))
929 senses.visionAngle = def.GetParameter("visionAngle")->AsFloat();
930
931 if (def.HasParameter("hearingRadius"))
932 senses.hearingRadius = def.GetParameter("hearingRadius")->AsFloat();
933 else if (def.HasParameter("hearingRange"))
934 senses.hearingRadius = def.GetParameter("hearingRange")->AsFloat();
935
936 if (def.HasParameter("perceptionHz"))
937 senses.perceptionHz = def.GetParameter("perceptionHz")->AsFloat();
938
939 if (def.HasParameter("thinkHz"))
940 senses.thinkHz = def.GetParameter("thinkHz")->AsFloat();
941
942 // DO NOT call AddComponent() - component is already modified by reference
943 return true;
944}
945
947{
949
950 // Extract width and height
951 if (def.HasParameter("width") && def.HasParameter("height"))
952 {
953 bbox.boundingBox.w = def.GetParameter("width")->AsFloat();
954 bbox.boundingBox.h = def.GetParameter("height")->AsFloat();
955
956 // Optional x, y offset
957 if (def.HasParameter("x"))
958 bbox.boundingBox.x = def.GetParameter("x")->AsFloat();
959 if (def.HasParameter("y"))
960 bbox.boundingBox.y = def.GetParameter("y")->AsFloat();
961
962 // Optional offsetX, offsetY (alternative to x,y)
963 if (def.HasParameter("offsetX"))
964 bbox.boundingBox.x = def.GetParameter("offsetX")->AsFloat();
965 if (def.HasParameter("offsetY"))
966 bbox.boundingBox.y = def.GetParameter("offsetY")->AsFloat();
967 }
968
970 return true;
971}
972
974{
976
977 // Extract direction
978 if (def.HasParameter("direction"))
979 {
980 movement.direction = def.GetParameter("direction")->AsVector();
981 }
982 else if (def.HasParameter("directionX") && def.HasParameter("directionY"))
983 {
984 float x = def.GetParameter("directionX")->AsFloat();
985 float y = def.GetParameter("directionY")->AsFloat();
986 movement.direction = Vector(x, y, 0.0f);
987 }
988
989 // Extract velocity
990 if (def.HasParameter("velocity"))
991 {
992 movement.velocity = def.GetParameter("velocity")->AsVector();
993 }
994 else if (def.HasParameter("velocityX") && def.HasParameter("velocityY"))
995 {
996 float x = def.GetParameter("velocityX")->AsFloat();
997 float y = def.GetParameter("velocityY")->AsFloat();
998 movement.velocity = Vector(x, y, 0.0f);
999 }
1000
1002 return true;
1003}
1004
1006{
1008
1009 // Extract health parameters
1010 if (def.HasParameter("currentHealth"))
1011 health.currentHealth = def.GetParameter("currentHealth")->AsInt();
1012
1013 if (def.HasParameter("maxHealth"))
1014 health.maxHealth = def.GetParameter("maxHealth")->AsInt();
1015
1016
1018 return true;
1019}
1020
1022{
1024
1025 // Extract radius
1026 if (def.HasParameter("radius"))
1027 trigger.radius = def.GetParameter("radius")->AsFloat();
1028
1029 if (def.HasParameter("triggered"))
1030 trigger.triggered = def.GetParameter("triggered")->AsBool();
1031
1033 return true;
1034}
1035
1037{
1038 CollisionZone_data collision;
1039
1040 // Extract bounds
1041 if (def.HasParameter("x") && def.HasParameter("y") &&
1042 def.HasParameter("width") && def.HasParameter("height"))
1043 {
1044 collision.bounds.x = def.GetParameter("x")->AsFloat();
1045 collision.bounds.y = def.GetParameter("y")->AsFloat();
1046 collision.bounds.w = def.GetParameter("width")->AsFloat();
1047 collision.bounds.h = def.GetParameter("height")->AsFloat();
1048 }
1049
1050 if (def.HasParameter("isStatic"))
1051 collision.isStatic = def.GetParameter("isStatic")->AsBool();
1052
1053 World::Get().AddComponent<CollisionZone_data>(entity, collision);
1054 return true;
1055}
1056
1058{
1059 Animation_data animation;
1060
1061 // Extract animation parameters
1062 if (def.HasParameter("animationID"))
1063 animation.animationID = def.GetParameter("animationID")->AsString();
1064
1065 if (def.HasParameter("frameDuration"))
1066 animation.frameDuration = def.GetParameter("frameDuration")->AsFloat();
1067
1068 if (def.HasParameter("currentFrame"))
1069 animation.currentFrame = def.GetParameter("currentFrame")->AsInt();
1070
1071 World::Get().AddComponent<Animation_data>(entity, animation);
1072 return true;
1073}
1074
1076{
1077 FX_data fx;
1078
1079 // Extract FX parameters
1080 if (def.HasParameter("effectType"))
1081 fx.effectType = def.GetParameter("effectType")->AsString();
1082
1083 if (def.HasParameter("duration"))
1084 fx.duration = def.GetParameter("duration")->AsFloat();
1085
1086 World::Get().AddComponent<FX_data>(entity, fx);
1087 return true;
1088}
1089
1091{
1092 AudioSource_data audio;
1093
1094 // Extract audio parameters
1095 if (def.HasParameter("soundEffectID"))
1096 audio.soundEffectID = def.GetParameter("soundEffectID")->AsString();
1097
1098 if (def.HasParameter("volume"))
1099 audio.volume = def.GetParameter("volume")->AsFloat();
1100
1101 World::Get().AddComponent<AudioSource_data>(entity, audio);
1102 return true;
1103}
1104
1106{
1108
1109 // Extract controller parameters
1110 if (def.HasParameter("controllerID"))
1111 controller.controllerID = static_cast<short>(def.GetParameter("controllerID")->AsInt());
1112 else
1113 {
1114 controller.controllerID = -1;
1115 }
1116
1117
1118 if (def.HasParameter("isConnected"))
1119 controller.isConnected = def.GetParameter("isConnected")->AsBool();
1120
1122 return true;
1123}
1124
1126{
1128
1129 // Extract player controller parameters
1130 if (def.HasParameter("isJumping"))
1131 playerCtrl.isJumping = def.GetParameter("isJumping")->AsBool();
1132
1133 if (def.HasParameter("isShooting"))
1134 playerCtrl.isShooting = def.GetParameter("isShooting")->AsBool();
1135
1136 if (def.HasParameter("isRunning"))
1137 playerCtrl.isRunning = def.GetParameter("isRunning")->AsBool();
1138
1139 if (def.HasParameter("isInteracting"))
1140 playerCtrl.isInteracting = def.GetParameter("isInteracting")->AsBool();
1141
1142 if (def.HasParameter("isWalking"))
1143 playerCtrl.isWalking = def.GetParameter("isWalking")->AsBool();
1144
1145 if (def.HasParameter("isUsingItem"))
1146 playerCtrl.isUsingItem = def.GetParameter("isUsingItem")->AsBool();
1147
1148 if (def.HasParameter("isMenuOpen"))
1149 playerCtrl.isMenuOpen = def.GetParameter("isMenuOpen")->AsBool();
1150
1152 return true;
1153}
1154
1156{
1158
1159 // Extract binding parameters
1160 if (def.HasParameter("playerIndex"))
1161 binding.playerIndex = static_cast<short>(def.GetParameter("playerIndex")->AsInt());
1162
1163 if (def.HasParameter("controllerID"))
1164 binding.controllerID = static_cast<short>(def.GetParameter("controllerID")->AsInt());
1165
1167
1168 return true;
1169}
1170
1172{
1173 NPC_data npc;
1174
1175 // Extract NPC type
1176 if (def.HasParameter("npcType"))
1177 npc.npcType = def.GetParameter("npcType")->AsString();
1178
1179 World::Get().AddComponent<NPC_data>(entity, npc);
1180 return true;
1181}
1182
1184{
1186
1187 // Note: Items are typically added dynamically during gameplay
1188 // We don't extract items from the definition here
1189
1191 return true;
1192}
1193
1195{
1197
1198 // Extract camera parameters
1199 if (def.HasParameter("playerId"))
1200 camera.playerId = static_cast<short>(def.GetParameter("playerId")->AsInt());
1201
1202 if (def.HasParameter("zoom"))
1203 camera.zoom = def.GetParameter("zoom")->AsFloat();
1204
1205 if (def.HasParameter("targetZoom"))
1206 camera.targetZoom = def.GetParameter("targetZoom")->AsFloat();
1207
1208 if (def.HasParameter("position"))
1209 camera.position = def.GetParameter("position")->AsVector();
1210
1212 return true;
1213}
1214
1216{
1217 CameraTarget_data target;
1218
1219 // Extract target parameters
1220 if (def.HasParameter("targetEntityID"))
1221 target.targetEntityID = def.GetParameter("targetEntityID")->AsEntityRef();
1222
1223 if (def.HasParameter("followTarget"))
1224 target.followTarget = def.GetParameter("followTarget")->AsBool();
1225
1226 if (def.HasParameter("smoothFactor"))
1227 target.smoothFactor = def.GetParameter("smoothFactor")->AsFloat();
1228
1229 World::Get().AddComponent<CameraTarget_data>(entity, target);
1230 return true;
1231}
1232
1234{
1236
1237 // Extract effects parameters
1238 if (def.HasParameter("isShaking"))
1239 effects.isShaking = def.GetParameter("isShaking")->AsBool();
1240
1241 if (def.HasParameter("shakeIntensity"))
1242 effects.shakeIntensity = def.GetParameter("shakeIntensity")->AsFloat();
1243
1244 if (def.HasParameter("shakeDuration"))
1245 effects.shakeDuration = def.GetParameter("shakeDuration")->AsFloat();
1246
1248 return true;
1249}
1250
1252{
1253 CameraBounds_data bounds;
1254
1255 // Extract bounds parameters
1256 if (def.HasParameter("useBounds"))
1257 bounds.useBounds = def.GetParameter("useBounds")->AsBool();
1258
1259 if (def.HasParameter("x") && def.HasParameter("y") &&
1260 def.HasParameter("width") && def.HasParameter("height"))
1261 {
1262 bounds.boundingBox.x = def.GetParameter("x")->AsFloat();
1263 bounds.boundingBox.y = def.GetParameter("y")->AsFloat();
1264 bounds.boundingBox.w = def.GetParameter("width")->AsFloat();
1265 bounds.boundingBox.h = def.GetParameter("height")->AsFloat();
1266 }
1267
1268 World::Get().AddComponent<CameraBounds_data>(entity, bounds);
1269 return true;
1270}
1271
1273{
1275
1276 // Extract input binding parameters
1277 if (def.HasParameter("playerId"))
1278 binding.playerId = static_cast<short>(def.GetParameter("playerId")->AsInt());
1279
1280 if (def.HasParameter("useKeyboard"))
1281 binding.useKeyboard = def.GetParameter("useKeyboard")->AsBool();
1282
1283 if (def.HasParameter("deadzone"))
1284 binding.deadzone = def.GetParameter("deadzone")->AsFloat();
1285
1287 return true;
1288}
1289
1291{
1293
1294 // Initialize with defaults
1296
1297 // Extract custom parameters if provided
1298 if (def.HasParameter("deadzone"))
1299 mapping.deadzone = def.GetParameter("deadzone")->AsFloat();
1300
1301 if (def.HasParameter("sensitivity"))
1302 mapping.sensitivity = def.GetParameter("sensitivity")->AsFloat();
1303
1305 return true;
1306}
1307
1309{
1310 // Get existing component created by auto-registration
1312 {
1313 SYSTEM_LOG << "[PrefabFactory] ERROR: NavigationAgent_data should exist (auto-registration)\n";
1314 return false;
1315 }
1316
1318
1319 // Apply parameters
1320 if (def.HasParameter("agentRadius"))
1321 navAgent.agentRadius = def.GetParameter("agentRadius")->AsFloat();
1322
1323 if (def.HasParameter("maxSpeed"))
1324 navAgent.maxSpeed = def.GetParameter("maxSpeed")->AsFloat();
1325
1326 if (def.HasParameter("layerMask"))
1327 navAgent.layerMask = static_cast<int>(def.GetParameter("layerMask")->AsInt());
1328
1329 return true;
1330}
1331
1333{
1335
1336 // Extract AI state parameters
1337 if (def.HasParameter("currentState"))
1338 {
1339 std::string stateStr = def.GetParameter("currentState")->AsString();
1340 // Convert string to AIMode enum
1341 if (stateStr == "Idle") aiState.currentMode = AIMode::Idle;
1342 else if (stateStr == "Patrol") aiState.currentMode = AIMode::Patrol;
1343 else if (stateStr == "Combat") aiState.currentMode = AIMode::Combat;
1344 else if (stateStr == "Flee") aiState.currentMode = AIMode::Flee;
1345 else if (stateStr == "Investigate") aiState.currentMode = AIMode::Investigate;
1346 else if (stateStr == "Dead") aiState.currentMode = AIMode::Dead;
1347 else {
1348 SYSTEM_LOG << "PrefabFactory::InstantiateAIState: Warning - Unknown state '"
1349 << stateStr << "', defaulting to Idle\n";
1350 }
1351 }
1352
1353 if (def.HasParameter("previousState"))
1354 {
1355 std::string stateStr = def.GetParameter("previousState")->AsString();
1356 if (stateStr == "Idle") aiState.previousMode = AIMode::Idle;
1357 else if (stateStr == "Patrol") aiState.previousMode = AIMode::Patrol;
1358 else if (stateStr == "Combat") aiState.previousMode = AIMode::Combat;
1359 else if (stateStr == "Flee") aiState.previousMode = AIMode::Flee;
1360 else if (stateStr == "Investigate") aiState.previousMode = AIMode::Investigate;
1361 else if (stateStr == "Dead") aiState.previousMode = AIMode::Dead;
1362 else {
1363 SYSTEM_LOG << "PrefabFactory::InstantiateAIState: Warning - Unknown previousState '"
1364 << stateStr << "', defaulting to Idle\n";
1365 }
1366 }
1367
1368 if (def.HasParameter("combatEngageDistance"))
1369 aiState.combatEngageDistance = def.GetParameter("combatEngageDistance")->AsFloat();
1370
1371 if (def.HasParameter("fleeHealthThreshold"))
1372 aiState.fleeHealthThreshold = def.GetParameter("fleeHealthThreshold")->AsFloat();
1373
1374 if (def.HasParameter("investigateTimeout"))
1375 aiState.investigateTimeout = def.GetParameter("investigateTimeout")->AsFloat();
1376
1378 return true;
1379}
1380
1382{
1383 // Get the EXISTING component created by auto-registration
1385 {
1386 std::cerr << "[PrefabFactory] ERROR: BehaviorTreeRuntime_data not found for entity " << entity << std::endl;
1387 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
1388 return false;
1389 }
1390
1391 // Get reference to existing component (not a copy)
1393
1394 // Extract behavior tree runtime parameters
1395 // Support both old and new property names for backward compatibility
1396
1397 // Check for treeAssetId (old) or AITreeAssetId (new)
1398 if (def.HasParameter("AITreeAssetId"))
1399 {
1400 btRuntime.AITreeAssetId = static_cast<uint32_t>(def.GetParameter("AITreeAssetId")->AsInt());
1401 std::cerr << "[PrefabFactory] Entity " << entity << " AITreeAssetId set to " << btRuntime.AITreeAssetId << std::endl;
1402 }
1403 else if (def.HasParameter("treeAssetId"))
1404 {
1405 btRuntime.AITreeAssetId = static_cast<uint32_t>(def.GetParameter("treeAssetId")->AsInt());
1406 std::cerr << "[PrefabFactory] Entity " << entity << " treeAssetId (old) set to " << btRuntime.AITreeAssetId << std::endl;
1407 }
1408
1409 // Check for treePath (old) or AITreePath (new)
1410 std::string treePath;
1411 if (def.HasParameter("AITreePath"))
1412 {
1413 treePath = def.GetParameter("AITreePath")->AsString();
1414 }
1415 else if (def.HasParameter("treePath"))
1416 {
1417 treePath = def.GetParameter("treePath")->AsString();
1418 }
1419
1420 if (!treePath.empty())
1421 {
1422 Identity_data* identity = nullptr;
1423 if (World::Get().HasComponent<Identity_data>(entity))
1425
1426 // Map treePath -> treeId using the registry
1427 btRuntime.AITreePath = treePath;
1428
1430 btRuntime.AITreeAssetId = treeId;
1431
1432 if (identity != nullptr)
1433 std::cerr << "[PrefabFactory] Mapped BehaviorTree: " << treePath << " -> ID " << treeId << " for entity " << identity->name << std::endl;
1434 else
1435 std::cerr << "[PrefabFactory] Mapped BehaviorTree: " << treePath << " -> ID " << treeId << " for entity " << entity << std::endl;
1436
1437 // Verify the tree is loaded
1439 if (!tree)
1440 {
1441 std::cerr << "[PrefabFactory] WARNING: BehaviorTree not loaded: " << treePath
1442 << " (ID=" << treeId << ") - this should not happen if dependencies were loaded correctly" << std::endl;
1443 }
1444 }
1445
1446 if (def.HasParameter("active"))
1447 btRuntime.isActive = def.GetParameter("active")->AsBool();
1448
1449 // Support both old and new property names for currentNodeIndex
1450 if (def.HasParameter("AICurrentNodeIndex"))
1451 btRuntime.AICurrentNodeIndex = static_cast<uint32_t>(def.GetParameter("AICurrentNodeIndex")->AsInt());
1452 else if (def.HasParameter("currentNodeIndex"))
1453 btRuntime.AICurrentNodeIndex = static_cast<uint32_t>(def.GetParameter("currentNodeIndex")->AsInt());
1454
1455 // DO NOT call AddComponent() - component is already modified by reference
1456 return true;
1457}
1458
1460{
1461 // Get the EXISTING component created by auto-registration
1463 {
1464 std::cerr << "[PrefabFactory] ERROR: MoveIntent_data not found for entity " << entity << std::endl;
1465 std::cerr << "[PrefabFactory] This should have been created by auto-registration!" << std::endl;
1466 return false;
1467 }
1468
1469 // Get reference to existing component (not a copy)
1471
1472 // Extract move intent parameters
1473 if (def.HasParameter("targetX") && def.HasParameter("targetY"))
1474 {
1475 float x = def.GetParameter("targetX")->AsFloat();
1476 float y = def.GetParameter("targetY")->AsFloat();
1477 moveIntent.targetPosition = Vector(x, y, 0.0f);
1478 }
1479
1480 if (def.HasParameter("targetPosition"))
1481 moveIntent.targetPosition = def.GetParameter("targetPosition")->AsVector();
1482
1483 if (def.HasParameter("desiredSpeed"))
1484 moveIntent.desiredSpeed = def.GetParameter("desiredSpeed")->AsFloat();
1485
1486 if (def.HasParameter("hasTarget"))
1487 moveIntent.hasIntent = def.GetParameter("hasTarget")->AsBool();
1488
1489 if (def.HasParameter("hasIntent"))
1490 moveIntent.hasIntent = def.GetParameter("hasIntent")->AsBool();
1491
1492 if (def.HasParameter("arrivalThreshold"))
1493 moveIntent.arrivalThreshold = def.GetParameter("arrivalThreshold")->AsFloat();
1494
1495 if (def.HasParameter("usePathfinding"))
1496 moveIntent.usePathfinding = def.GetParameter("usePathfinding")->AsBool();
1497
1498 if (def.HasParameter("avoidObstacles"))
1499 moveIntent.avoidObstacles = def.GetParameter("avoidObstacles")->AsBool();
1500
1501 // DO NOT call AddComponent() - component is already modified by reference
1502 return true;
1503}
1504
1506{
1508
1509 // Extract attack intent parameters
1510 if (def.HasParameter("targetEntity"))
1511 attackIntent.targetEntity = def.GetParameter("targetEntity")->AsEntityRef();
1512
1513 if (def.HasParameter("targetPosition"))
1514 attackIntent.targetPosition = def.GetParameter("targetPosition")->AsVector();
1515
1516 if (def.HasParameter("damage"))
1517 attackIntent.damage = def.GetParameter("damage")->AsFloat();
1518
1519 if (def.HasParameter("range"))
1520 attackIntent.range = def.GetParameter("range")->AsFloat();
1521
1522 if (def.HasParameter("attackRange"))
1523 attackIntent.range = def.GetParameter("attackRange")->AsFloat();
1524
1525 if (def.HasParameter("hasIntent"))
1526 attackIntent.hasIntent = def.GetParameter("hasIntent")->AsBool();
1527
1528 if (def.HasParameter("cooldown"))
1529 attackIntent.cooldown = def.GetParameter("cooldown")->AsFloat();
1530
1531 if (def.HasParameter("attackType"))
1532 {
1533 std::string typeStr = def.GetParameter("attackType")->AsString();
1534 if (typeStr == "Melee") attackIntent.attackType = AttackIntent_data::AttackType::Melee;
1535 else if (typeStr == "Ranged") attackIntent.attackType = AttackIntent_data::AttackType::Ranged;
1536 else if (typeStr == "Area") attackIntent.attackType = AttackIntent_data::AttackType::Area;
1537 else {
1538 SYSTEM_LOG << "PrefabFactory::InstantiateAttackIntent: Warning - Unknown attackType '"
1539 << typeStr << "', defaulting to Melee\n";
1540 }
1541 }
1542
1544 return true;
1545}
Data-driven behavior tree system for AI decision making.
Core ECS component definitions.
RenderLayer
Render layer enumeration for Z-ordering.
@ Investigate
ComponentTypeID GetComponentTypeID_Static()
Definition ECS_Entity.h:56
std::uint64_t EntityID
Definition ECS_Entity.h:21
const EntityID INVALID_ENTITY_ID
Definition ECS_Entity.h:23
EntityType
Definition GameObject.h:22
static EntityType StringToEntityType(const std::string &typeStr)
void RegisterComponentFactory_Internal(const char *componentName, std::function< bool(EntityID, const ComponentDefinition &)> factory)
World and ECS Manager for Olympe Engine.
uint32_t GetTreeIdFromPath(const std::string &treePath) const
const BehaviorTreeAsset * GetTree(uint32_t treeId) const
static BehaviorTreeManager & Get()
static DataManager & Get()
Definition DataManager.h:91
Sprite * GetSprite(const std::string &id, const std::string &path, ResourceCategory category=ResourceCategory::GameEntity)
std::vector< ResolvedComponentInstance > Resolve(const PrefabBlueprint &prefab, const LevelInstanceParameters &instanceParams)
bool InstantiatePosition(EntityID entity, const ComponentDefinition &def)
bool InstantiateAIBehavior(EntityID entity, const ComponentDefinition &def)
void RegisterComponentFactory(const std::string &componentName, std::function< bool(EntityID, const ComponentDefinition &)> factory)
Register a component factory (called by auto-registration system)
bool InstantiateComponent(EntityID entity, const ComponentDefinition &componentDef)
Instantiate a single component on an entity.
bool InstantiateAttackIntent(EntityID entity, const ComponentDefinition &def)
bool InstantiateAudioSource(EntityID entity, const ComponentDefinition &def)
bool InstantiateCameraEffects(EntityID entity, const ComponentDefinition &def)
std::unique_ptr< PrefabScanner > m_scanner
std::map< std::string, std::function< bool(EntityID, const ComponentDefinition &)> > m_componentFactories
bool InstantiateCameraBounds(EntityID entity, const ComponentDefinition &def)
bool IsComponentRegistered(const std::string &componentName) const
Check if a component is registered.
bool InstantiatePhysicsBody(EntityID entity, const ComponentDefinition &def)
bool InstantiateCamera(EntityID entity, const ComponentDefinition &def)
bool InstantiatePlayerController(EntityID entity, const ComponentDefinition &def)
std::string NormalizeType(const std::string &type) const
Normalize a type string to canonical form.
bool InstantiateAIBlackboard(EntityID entity, const ComponentDefinition &def)
PrefabRegistry m_prefabRegistry
bool AreTypesEquivalent(const std::string &type1, const std::string &type2) const
Check if two types are equivalent.
bool InstantiateController(EntityID entity, const ComponentDefinition &def)
bool GetCanonicalInfo(const std::string &type, std::string &outCanonical, std::string &outPrefabFile) const
Get canonical type info for debugging.
void SetPrefabRegistry(const PrefabRegistry &registry)
Set the prefab registry cache.
bool IsTypeRegistered(const std::string &type) const
Check if a type is registered.
bool InstantiateBoundingBox(EntityID entity, const ComponentDefinition &def)
EntityID CreateEntityWithOverrides(const PrefabBlueprint &blueprint, const LevelInstanceParameters &instanceParams, bool autoAssignLayer=true)
Create entity from blueprint with level instance parameter overrides.
bool InstantiateVisualSprite(EntityID entity, const ComponentDefinition &def)
bool InstantiateVisualAnimation(EntityID entity, const ComponentDefinition &def)
bool InstantiateMoveIntent(EntityID entity, const ComponentDefinition &def)
std::vector< std::string > GetRegisteredComponents() const
Get list of all registered components (for debugging)
bool InstantiatePlayerBinding(EntityID entity, const ComponentDefinition &def)
bool InstantiateBehaviorTreeRuntime(EntityID entity, const ComponentDefinition &def)
EntityID CreateEntityFromBlueprint(const PrefabBlueprint &blueprint, bool autoAssignLayer=true)
Create entity from a parsed blueprint.
bool InstantiateCollisionZone(EntityID entity, const ComponentDefinition &def)
std::map< std::string, PrefabBuilder > m_prefabs
bool InstantiateVisualEditor(EntityID entity, const ComponentDefinition &def)
bool InstantiateFX(EntityID entity, const ComponentDefinition &def)
bool InstantiateAIState(EntityID entity, const ComponentDefinition &def)
static PrefabFactory & Get()
Get singleton instance.
bool InstantiateInputMapping(EntityID entity, const ComponentDefinition &def)
bool InstantiateNavigationAgent(EntityID entity, const ComponentDefinition &def)
bool InstantiateCameraInputBinding(EntityID entity, const ComponentDefinition &def)
bool InstantiateAISenses(EntityID entity, const ComponentDefinition &def)
bool InstantiateIdentity(EntityID entity, const ComponentDefinition &def)
EntityID CreateEntity(const std::string &prefabName)
Create an entity using legacy prefab system.
EntityID CreateEntityFromPrefabName(const std::string &prefabName)
Create entity from prefab name.
bool InstantiateAnimation(EntityID entity, const ComponentDefinition &def)
bool InstantiateHealth(EntityID entity, const ComponentDefinition &def)
bool InstantiateNPC(EntityID entity, const ComponentDefinition &def)
void PreloadAllPrefabs(const std::string &prefabDirectory="Blueprints/EntityPrefab")
Preload all prefabs from directory.
bool InstantiateTriggerZone(EntityID entity, const ComponentDefinition &def)
bool InstantiateMovement(EntityID entity, const ComponentDefinition &def)
bool InstantiateInventory(EntityID entity, const ComponentDefinition &def)
bool InstantiateCameraTarget(EntityID entity, const ComponentDefinition &def)
const PrefabBlueprint * Find(const std::string &name) const
std::vector< std::string > GetAllPrefabNames() const
int GetCount() const
Core ECS manager and world coordinator.
Definition World.h:210
static World & Get()
Get singleton instance (short form)
Definition World.h:232
T & AddComponent(EntityID entity, Args &&... args)
Definition World.h:393
bool HasComponent(EntityID entity) const
Definition World.h:451
RenderLayer GetDefaultLayerForType(EntityType type) const
Get the default render layer for an entity type Automatically assigns appropriate layer based on enti...
Definition World.h:473
T & GetComponent(EntityID entity)
Definition World.h:438
EntityID CreateEntity()
Definition World.cpp:225
void SetEntityLayer(EntityID entity, RenderLayer layer)
Set entity render layer (updates position.z)
Definition World.cpp:292
Header file for PrefabFactory class, responsible for creating game object prefabs.
std::string behaviorType
std::string animationID
std::string soundEffectID
Bounding box component for collision detection.
SDL_FRect boundingBox
Collision rectangle.
const ComponentParameter * GetParameter(const std::string &name) const
bool HasParameter(const std::string &name) const
EntityID AsEntityRef() const
std::string AsString() const
SDL_Color AsColor() const
std::string effectType
Identity component for entity identification.
std::string name
Entity name identifier.
std::string npcType
Position component for spatial location.
Vector position
2D/3D position vector
std::vector< ComponentDefinition > components
ECS component for animated sprites.
#define SYSTEM_LOG