ChristianWiele
Active member
Hi,
as you might know, there is currently no officical integration for UIS and UCC with the PUN multiplayer add-on. Still I wanted to use UIS for my project so I started building my own integration. It's not done yet but I thought it might be a good idea to continue it as a community-driven solution from here. This way more of you can benefit from / test the solution, and we might help @Justin to quicker get to an official solution. Unfortunately, the current solution requires the modification of Opsive code, so anytime the PUN add-on is updated you have to manually add the required changes.
These are the areas I have worked on / identified so far:
* basic equip / uneqip
* sync items on player entering room (open)
* pickup / drop (mostly open)
* UI
* crafting
Enjoy, and let's drive this jointly forward.
BTW, don't try this at home, if you know what I mean
--- EQUIP/UNEQUIP ---
This part gave me the biggest headaches as UIS and UCC use fundamentally different mechanisms to add / remove items to the character.
UCC with its simple inventory use the following mechanism to add / equip items across the network:
* all equippable items need to be added to the RuntimePickup component of the PunGame gameobject
* as the character spawns all these items are added as children to the Items gameobject of the character
* each item has a static / fixed itemIdentifierID
* upon equip/unequip the PunCharacter component sends this itemIdentifierID to the remote machines
* on the remote machine the item is resolved using the ItemIdentifierTracker which provides a static mapping between itemIdentifierID and the corresponding item
* the corresponding gameobjects of the equipped / unequipped item are then activated / deactivated
The UIS uses a different approach:
* first there are different stages in the inventory (item collections). If you want to equip an item it first has to be moved into the Equippable item collections
* only if an item is in the Equippable collection the corresponding gameobjects are added dynamically to the character
* each item has a random itemIdentifierID which might change upon respawn (this is an instance ID while in UCC this is a class ID)
* in addition each item has a fixed itemIdentifierDefinitionID (class ID)
The main issue is the dynamic itemIdentifierID in UIS. I tried to find the least invasive solution, but the only way was to modify the PunCharacter and ItemIdentifierTracker scripts
* the PunCharacter resolves the itemIdentifierDefinitionID, and sends both itemIdentifierID and itemIdentifierDefinitionID to the remote client
* the ItemIdentifierTracker is modified to allow for registration of the dynamic itemIdentifierID
* each time the equipped/unequipped item is changed, a corresponding item is created/destroyed on the remote side.
In the following I only list the added/modified methods in the two scripts.
I added these methods to the ItemIdentifierTracker.cs. These methods allow to dynamically add and remove itemIdentifier IDs. These modifications have to be done in the original file as the PUN add-on accesses the ItemIdentifierTracker through static class methods.
And here are the modifications for the PunCharacter script. You can copy the PunCharacter script to something like PunCharacter4UIS and do the modifications in the copy. Then the modifications are not overridden when importing an update to the PUN add-on. Still you have to manually check for code changes in the PunCharacter then.
--- SYNC STATE (open) ---
I have not yet adapted the OnPlayerEnteredRoom method and the corresponding RPCs of the PunCharacter script. This method syncs the items when a new player enters the room.
--- PICKUP / DROP ---
Pickups work if you don't want to don't need the ability to also drop them.
* use the InventorItemPickup script (UCC method for pickups)
* add PhotonView, PunRespawnMonitor, PunNetworkInfo, PunLocationMonitor
* disable "Pickup On Trigger Enter", I ran into issues with this enabled
For pickups to be droppable a new script is required that corresponds to the PunItemPickup script for UCC. This script sets up the pickup on remote machines. Should not a big deal, but had no time and need so far to do it.
(Holy cow, exceeding 10.000 characters so I have to split the post ...)
as you might know, there is currently no officical integration for UIS and UCC with the PUN multiplayer add-on. Still I wanted to use UIS for my project so I started building my own integration. It's not done yet but I thought it might be a good idea to continue it as a community-driven solution from here. This way more of you can benefit from / test the solution, and we might help @Justin to quicker get to an official solution. Unfortunately, the current solution requires the modification of Opsive code, so anytime the PUN add-on is updated you have to manually add the required changes.
These are the areas I have worked on / identified so far:
* basic equip / uneqip
* sync items on player entering room (open)
* pickup / drop (mostly open)
* UI
* crafting
Enjoy, and let's drive this jointly forward.
BTW, don't try this at home, if you know what I mean
--- EQUIP/UNEQUIP ---
This part gave me the biggest headaches as UIS and UCC use fundamentally different mechanisms to add / remove items to the character.
UCC with its simple inventory use the following mechanism to add / equip items across the network:
* all equippable items need to be added to the RuntimePickup component of the PunGame gameobject
* as the character spawns all these items are added as children to the Items gameobject of the character
* each item has a static / fixed itemIdentifierID
* upon equip/unequip the PunCharacter component sends this itemIdentifierID to the remote machines
* on the remote machine the item is resolved using the ItemIdentifierTracker which provides a static mapping between itemIdentifierID and the corresponding item
* the corresponding gameobjects of the equipped / unequipped item are then activated / deactivated
The UIS uses a different approach:
* first there are different stages in the inventory (item collections). If you want to equip an item it first has to be moved into the Equippable item collections
* only if an item is in the Equippable collection the corresponding gameobjects are added dynamically to the character
* each item has a random itemIdentifierID which might change upon respawn (this is an instance ID while in UCC this is a class ID)
* in addition each item has a fixed itemIdentifierDefinitionID (class ID)
The main issue is the dynamic itemIdentifierID in UIS. I tried to find the least invasive solution, but the only way was to modify the PunCharacter and ItemIdentifierTracker scripts
* the PunCharacter resolves the itemIdentifierDefinitionID, and sends both itemIdentifierID and itemIdentifierDefinitionID to the remote client
* the ItemIdentifierTracker is modified to allow for registration of the dynamic itemIdentifierID
* each time the equipped/unequipped item is changed, a corresponding item is created/destroyed on the remote side.
In the following I only list the added/modified methods in the two scripts.
I added these methods to the ItemIdentifierTracker.cs. These methods allow to dynamically add and remove itemIdentifier IDs. These modifications have to be done in the original file as the PUN add-on accesses the ItemIdentifierTracker through static class methods.
Code:
public static void AddItemIdentifier(uint id, IItemIdentifier itemIdentifier)
{
Instance.AddItemIdentifierInternal(id, itemIdentifier);
}
public void AddItemIdentifierInternal(uint id, IItemIdentifier itemIdentifier)
{
if(m_IDItemIdentifierMap.TryGetValue(id, out var existingItemIdentifier))
{
return;
}
m_IDItemIdentifierMap.Add(id, itemIdentifier);
}
public static void RemoveItemIdentifier(uint id)
{
Instance.RemoveItemIdentifierInternal(id);
}
public void RemoveItemIdentifierInternal(uint id)
{
if(!m_IDItemIdentifierMap.TryGetValue(id, out var existingItemIdentifier))
{
return;
}
m_IDItemIdentifierMap.Remove(id);
}
And here are the modifications for the PunCharacter script. You can copy the PunCharacter script to something like PunCharacter4UIS and do the modifications in the copy. Then the modifications are not overridden when importing an update to the PUN add-on. Still you have to manually check for code changes in the PunCharacter then.
Code:
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateCharacterController.Integrations.UltimateInventorySystem;
private void Awake()
{
m_GameObject = gameObject;
m_CharacterLocomotion = m_GameObject.GetCachedComponent<UltimateCharacterLocomotion>();
m_Inventory = m_GameObject.GetCachedComponent<InventoryBase>();
// Added for the UIS integration
characterInventoryBridge = m_GameObject.GetCachedComponent<CharacterInventoryBridge>();
}
public void EquipUnequipItem(uint itemIdentifierID, int slotID, bool equip)
{
var inventoryItemDefinitionID = InventorySystemManager.GetItem(itemIdentifierID).ItemDefinition.ID;
photonView.RPC("EquipUnequipItemRPC", RpcTarget.Others, itemIdentifierID, inventoryItemDefinitionID, slotID, equip);
}
[PunRPC]
private void EquipUnequipItemRPC(uint itemIdentifierID, uint inventoryItemDefinitionID, int slotID, bool equip)
{
if (equip) {
// The character has to be alive to equip.
if (!m_CharacterLocomotion.Alive)
{
return;
}
PickupItems();
// Register Item if it is not already registered
if(ItemIdentifierTracker.GetItemIdentifier(itemIdentifierID) == null )
{
var addedItem = AddItemToEquippable(itemIdentifierID, inventoryItemDefinitionID);
RegisterItem(addedItem);
}
}
var itemIdentifier = ItemIdentifierTracker.GetItemIdentifier(itemIdentifierID);
if (itemIdentifier == null) {
return;
}
var item = m_Inventory.GetItem(itemIdentifier, slotID);
if (item == null) {
return;
}
if (equip) {
if (m_Inventory.GetActiveItem(slotID) != item) {
EventHandler.ExecuteEvent<Opsive.UltimateCharacterController.Items.Item, int>(m_GameObject, "OnAbilityWillEquipItem", item, slotID);
m_Inventory.EquipItem(itemIdentifier, slotID, true);
}
} else {
EventHandler.ExecuteEvent<Opsive.UltimateCharacterController.Items.Item, int>(m_GameObject, "OnAbilityUnequipItemComplete", item, slotID);
m_Inventory.UnequipItem(itemIdentifier, slotID);
m_Inventory.RemoveItem(itemIdentifier, slotID, 0, false);
InventorySystemManager.ItemRegister.Unregister(itemIdentifierID);
UnRegisterItem(itemIdentifierID);
}
}
public void ItemIdentifierPickup(uint itemIdentifierID, int amount, int slotID, bool immediatePickup, bool forceEquip)
{
}
private ItemInfo AddItemToEquippable(uint characterItemID, uint inventoryItemDefinitionID)
{
var itemInfo = GetItemInfo(characterItemID, inventoryItemDefinitionID);
var addedItem = characterInventoryBridge.EquippableItemCollections.AddItem(itemInfo);
return addedItem;
}
private ItemInfo GetItemInfo(uint characterItemID, uint inventoryItemDefinitionID)
{
var itemDefinition = InventorySystemManager.GetItemDefinition(inventoryItemDefinitionID);
var inventoryItem = InventorySystemManager.CreateItem(itemDefinition, characterItemID);
var itemAmount = new ItemAmount(inventoryItem, 1);
return new ItemInfo(itemAmount);
}
private void RegisterItem(ItemInfo itemInfo)
{
ItemIdentifierTracker.AddItemIdentifier(itemInfo.Item.ID, itemInfo.Item);
}
private void UnRegisterItem(uint itemID)
{
ItemIdentifierTracker.RemoveItemIdentifier(itemID);
}
--- SYNC STATE (open) ---
I have not yet adapted the OnPlayerEnteredRoom method and the corresponding RPCs of the PunCharacter script. This method syncs the items when a new player enters the room.
--- PICKUP / DROP ---
Pickups work if you don't want to don't need the ability to also drop them.
* use the InventorItemPickup script (UCC method for pickups)
* add PhotonView, PunRespawnMonitor, PunNetworkInfo, PunLocationMonitor
* disable "Pickup On Trigger Enter", I ran into issues with this enabled
For pickups to be droppable a new script is required that corresponds to the PunItemPickup script for UCC. This script sets up the pickup on remote machines. Should not a big deal, but had no time and need so far to do it.
(Holy cow, exceeding 10.000 characters so I have to split the post ...)