replaceitemwithnewlambdabase.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. /**@class ReplaceItemWithNewLambdaBase
  2. * @brief base class for transformation operations (creating one item from another)
  3. **/
  4. class ReplaceItemWithNewLambdaBase
  5. {
  6. EntityAI m_OldItem;
  7. string m_NewItemType;
  8. protected ref InventoryLocation m_OldLocation;
  9. protected ref InventoryLocation m_NewLocation;
  10. protected bool m_RemoveFromLocationPassed = false;
  11. private bool m_RemoveNetworkObjectInfoPassed = false;
  12. void ReplaceItemWithNewLambdaBase(EntityAI old_item, string new_item_type)
  13. {
  14. m_OldItem = old_item;
  15. m_NewItemType = new_item_type;
  16. }
  17. void OverrideNewLocation(InventoryLocation newLocation)
  18. {
  19. m_NewLocation = newLocation;
  20. }
  21. void VerifyItemTypeBySlotType() {}
  22. protected bool WantCreateNewEntity()
  23. {
  24. return m_NewLocation && m_NewItemType != string.Empty;
  25. }
  26. protected bool CanExecuteLambda()
  27. {
  28. if (m_OldItem)
  29. if (GameInventory.LocationCanRemoveEntity(m_OldLocation))
  30. //if (WantCreateNewEntity() GameInventory.LocationTestAddEntityType(m_NewItemType, true, true, false, true))
  31. return true;
  32. return false;
  33. }
  34. /**@fn PrepareLocations
  35. * @brief Step A. - prepare inventory locations
  36. **/
  37. protected bool PrepareLocations()
  38. {
  39. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step A) Prepare inventory locations, old_item=" + m_OldItem);
  40. m_OldLocation = new InventoryLocation;
  41. if (m_OldItem.GetInventory().GetCurrentInventoryLocation(m_OldLocation)) // A.1) store old location
  42. {
  43. if (m_NewLocation == null)
  44. {
  45. m_NewLocation = new InventoryLocation;
  46. m_NewLocation.CopyLocationFrom(m_OldLocation, true); // A.2) prepare new location from old
  47. //setting proper location type for ground pos
  48. if (!m_NewLocation.GetParent())
  49. {
  50. vector m4[4];
  51. Math3D.MatrixIdentity4(m4);
  52. m4[3] = m_NewLocation.GetPos();
  53. string path = "" + CFG_VEHICLESPATH + " " + m_NewItemType + " inherit_rotation";
  54. bool keep_rotation = GetGame().ConfigIsExisting(path) && GetGame().ConfigGetInt(path) > 0;
  55. if (m_OldLocation.GetType() == InventoryLocationType.GROUND && keep_rotation)
  56. {
  57. float dir[4];
  58. m_OldLocation.GetDir(dir);
  59. m_NewLocation.SetGroundEx(null,m_NewLocation.GetPos(),dir);
  60. }
  61. else
  62. {
  63. m_NewLocation.SetGround(null,m4);
  64. }
  65. }
  66. }
  67. return true;
  68. }
  69. else
  70. Error("[inv] ReplaceItemWithNewLambdaBase Step A.1) failed to get old_item inventory location");
  71. return false;
  72. }
  73. /**@fn RemoveOldItemFromLocation
  74. * @brief Step B. - free location for new item
  75. * @NOTE this operation does not delete the object, only removes it from inventory location
  76. **/
  77. protected void RemoveOldItemFromLocation()
  78. {
  79. if (!GameInventory.LocationRemoveEntity(m_OldLocation)) // B) remove entity from old inventory location (making it free for new item)
  80. {
  81. Error("[inv] ReplaceItemWithNewLambdaBase Step B) failed to remove old_item rom current inventory location");
  82. m_RemoveFromLocationPassed = false;
  83. }
  84. Print("[inv] ReplaceItemWithNewLambdaBase Step B) remove OK, loc=" + InventoryLocation.DumpToStringNullSafe(m_OldLocation));
  85. m_RemoveFromLocationPassed = true;
  86. }
  87. protected void UndoRemoveOldItemFromLocation()
  88. {
  89. if (!GameInventory.LocationAddEntity(m_OldLocation)) // B) undo
  90. Error("[inv] ReplaceItemWithNewLambdaBase Step B) failed to undo remove");
  91. Print("[inv] ReplaceItemWithNewLambdaBase Step B) undo remove OK, loc=" + InventoryLocation.DumpToStringNullSafe(m_OldLocation));
  92. }
  93. /**@fn RemoveNetworkObjectInfo
  94. * @brief Step C. - remove network part of the object
  95. * @NOTE this operation does not delete the object, only removes its network part (and deletes it on client)
  96. **/
  97. protected void RemoveNetworkObjectInfo()
  98. {
  99. GetGame().RemoteObjectTreeDelete(m_OldItem); // C) this forces server to send DeleteObject Message to client. This is needed for preserving the appearance of network operations on client (so that DeleteObject(old) arrives before CreateVehicle(new)). @NOTE: this does not delete the object on server, only it's network representation.
  100. // @NOTE: the item is not deleted right now on server, but rather after copying the properties in Step E)
  101. m_RemoveNetworkObjectInfoPassed = true;
  102. }
  103. protected void UndoRemoveNetworkObjectInfo()
  104. {
  105. GetGame().RemoteObjectTreeCreate(m_OldItem);
  106. }
  107. /**@fn CreateNewEntity
  108. * @brief Step D. - create new entity (LOCAL) with specified type
  109. *
  110. * @NOTE: if (!m_NewLocation || m_NewItemType.Empty) ==> this function does not create a new entity
  111. **/
  112. protected EntityAI CreateNewEntity()
  113. {
  114. if (WantCreateNewEntity())
  115. {
  116. VerifyItemTypeBySlotType();
  117. EntityAI new_item;
  118. switch (m_NewLocation.GetType())
  119. {
  120. case InventoryLocationType.GROUND:
  121. new_item = EntityAI.Cast(GetGame().CreateObjectEx(m_NewItemType,m_NewLocation.GetPos(),ECE_PLACE_ON_SURFACE|ECE_LOCAL));
  122. string path = "" + CFG_VEHICLESPATH + " " + m_NewItemType + " inherit_rotation";
  123. bool keep_rotation = GetGame().ConfigIsExisting(path) && GetGame().ConfigGetInt(path) > 0;
  124. if (keep_rotation)
  125. {
  126. new_item.SetOrientation(m_OldItem.GetOrientation()); //this one actually works...debug InventoryLocation
  127. }
  128. break;
  129. case InventoryLocationType.ATTACHMENT:
  130. // forces rawlocation in C++ to make location Valid
  131. m_NewLocation.SetAttachment(m_NewLocation.GetParent(), null, m_NewLocation.GetSlot());
  132. new_item = GameInventory.LocationCreateEntity(m_NewLocation, m_NewItemType, ECE_OBJECT_SWAP, RF_NONE);
  133. break;
  134. default:
  135. new_item = GameInventory.LocationCreateLocalEntity(m_NewLocation, m_NewItemType, ECE_OBJECT_SWAP, RF_NONE);
  136. break;
  137. }
  138. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step D) Created new new_item=" + new_item);
  139. if (new_item)
  140. {
  141. return new_item;
  142. }
  143. else
  144. {
  145. return null;
  146. /*InventoryLocation backupLocation = new InventoryLocation;
  147. vector mtx[4];
  148. Math3D.MatrixIdentity4(mtx);
  149. mtx[3] = m_OldItem.GetPosition();
  150. backupLocation.SetGround(null, mtx);
  151. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step D) plan B - creating=" + m_NewItemType + " at bkp loc=" + backupLocation.DumpToString() + ", but failed");
  152. new_item = GameInventory.LocationCreateLocalEntity(backupLocation, m_NewItemType,ECE_OBJECT_SWAP,RF_NONE); // create LOCAL new one on ground
  153. if (!new_item)
  154. {
  155. Error("[inv] ReplaceItemWithNewLambdaBase Step D) plan B - wanted to create=" + m_NewItemType + " at bkp loc=" + backupLocation.DumpToString() + ", but failed");
  156. return null;
  157. }
  158. return new_item;*/
  159. }
  160. }
  161. // user did not asked for new entity
  162. return null;
  163. }
  164. /**@fn CopyOldPropertiesToNew
  165. * @brief Step E. copy properties from old object to the created one
  166. *
  167. * @NOTE: This is supposed to be overriden in derived classes
  168. **/
  169. void CopyOldPropertiesToNew(notnull EntityAI old_item, EntityAI new_item)
  170. {
  171. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step E) Copying props " + old_item + " --> " + new_item);
  172. }
  173. /**@fn DeleteOldEntity
  174. * @brief Step F. - deletes physically old item
  175. **/
  176. protected void DeleteOldEntity()
  177. {
  178. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step F) delete old item=" + m_OldItem);
  179. m_OldItem.DeleteSafe();
  180. }
  181. /**@fn CreateNetworkObjectInfo
  182. * @brief Step G. - create NetworkObjectInfo for new item
  183. *
  184. * @NOTE: new_item can be null if the lambda did not create any item (intentionaly)
  185. **/
  186. protected void CreateNetworkObjectInfo(EntityAI new_item)
  187. {
  188. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step G) CreateNetworkObjectInfo =" + new_item);
  189. if (new_item)
  190. GetGame().RemoteObjectTreeCreate(new_item); // G) this forces server to send CreateVehicle Message to client. This is needed for preserving the appearance of network operations on client (so that DeleteObject(old) arrives before CreateVehicle(new)). @NOTE: this does not delete the object on server, only it's network representation.
  191. }
  192. /**@fn OnSuccess
  193. * @brief Step H. - notification on finish
  194. *
  195. * @NOTE: new_item can be null if the lambda did not create any item (intentionaly)
  196. **/
  197. protected void OnSuccess(EntityAI new_item)
  198. {
  199. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[inv] ReplaceItemWithNewLambdaBase Step H) OnSuccess=" + new_item);
  200. }
  201. /**@fn OnAbort
  202. * @brief Step Out - notification on abort
  203. *
  204. * @NOTE: new_item can be null if the lambda did not create any item (intentionaly)
  205. **/
  206. protected void OnAbort()
  207. {
  208. Print("Error [inv] ReplaceItemWithNewLambdaBase OnAbort");
  209. }
  210. void Execute(HumanInventoryWithFSM fsm_to_notify = null)
  211. {
  212. int t = GetGame().GetTime();
  213. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[syncinv] t=" + t + " lambda.Execute start ");
  214. // A) init
  215. bool prepared = PrepareLocations();
  216. if (prepared && CanExecuteLambda())
  217. {
  218. // B) rm old (and delete on client)
  219. RemoveOldItemFromLocation();
  220. if (!m_RemoveFromLocationPassed)
  221. {
  222. Error("[inv] ReplaceItemWithNewLambdaBase Step B) ABORT - failed while rm old item from loc=" + InventoryLocation.DumpToStringNullSafe(m_OldLocation));
  223. if (fsm_to_notify)
  224. fsm_to_notify.ProcessHandAbortEvent(new HandEventHumanCommandActionAborted(fsm_to_notify.GetManOwner()));
  225. OnAbort();
  226. return;
  227. }
  228. // C) rm NetworkObjectInfo from old item (+ send delete object tree to clients)
  229. RemoveNetworkObjectInfo();
  230. // D) mk new in place of old
  231. EntityAI new_item = CreateNewEntity();
  232. if (WantCreateNewEntity() && new_item == null)
  233. {
  234. //Error("[inv] ReplaceItemWithNewLambdaBase Step D) ABORT - wanted to create=" + m_NewItemType + " at loc=" + m_NewLocation.DumpToString() + ", but failed");
  235. Print("Error [inv] ReplaceItemWithNewLambdaBase Step D) ABORT - wanted to create=" + m_NewItemType + " at loc=" + InventoryLocation.DumpToStringNullSafe(m_NewLocation) + ", but failed");
  236. if (m_RemoveFromLocationPassed)
  237. UndoRemoveOldItemFromLocation();
  238. if (m_RemoveNetworkObjectInfoPassed)
  239. UndoRemoveNetworkObjectInfo();
  240. OnAbort();
  241. if (fsm_to_notify)
  242. fsm_to_notify.ProcessHandAbortEvent(new HandEventHumanCommandActionAborted(fsm_to_notify.GetManOwner()));
  243. return;
  244. }
  245. // E) cpy props
  246. CopyOldPropertiesToNew(m_OldItem, new_item);
  247. // F) del old
  248. DeleteOldEntity();
  249. // G) mk new NetworkObjectInfo
  250. CreateNetworkObjectInfo(new_item);
  251. // H) notification
  252. OnSuccess(new_item);
  253. }
  254. else
  255. {
  256. Print("[syncinv] warning, lambda cannot be executed, skipping!");
  257. if (fsm_to_notify)
  258. fsm_to_notify.ProcessHandAbortEvent(new HandEventHumanCommandActionAborted(fsm_to_notify.GetManOwner()));
  259. OnAbort();
  260. return;
  261. }
  262. int te = GetGame().GetTime();
  263. int dt = te - t;
  264. if (LogManager.IsInventoryHFSMLogEnable()) hndDebugPrint("[syncinv] te=" + te + " lambda.Execute end, exec time=" + dt);
  265. }
  266. string DumpToString()
  267. {
  268. string s = "{ old=" + m_OldItem + " newType=" + m_NewItemType + "}";
  269. return s;
  270. }
  271. };
  272. class ItemInventory : GameInventory
  273. {
  274. };