Utilizing World Shop Services

# Course Introduction

Let's try to use `WorldShopService` to make items and passes registered on the Web purchasable. Keep in mind that in an unreleased World, even if you release a product, you cannot actually sell it.

# WorldShopService

When using the registered product in the World, you must use `WorldShopService`. A user who has successfully made a purchase is entitled to receive the product provided by the creator.

# Use Example

Register items and passes. If you purchase the item, your potions immediately increases by 100; and if you press Attack after purchasing the pass, your portions see an additional increase of 15.

[gif](16757382237655b20a67b51774a548bdef6461ef14507)

#### Preparation

Follow [Registering Products](/docs?postId=581) to register the item and pass.

[{"Product Type":"Product Name","Item":"Potion Item","Pass":"Potion Add-on Pass"},{"Product Type":"Price","Item":"Free","Pass":"Free"},{"Product Type":"Sale Period","Item":"Indefinite","Pass":"Indefinite"},{"Product Type":"Product Thumbnail","Item":"[png](1669032688633b964bbc6fc0b4f5784c7bf5e7461f58f)","Pass":"[png](1669032702800d3d79eebd2dd463990f7b0fe404b06e7)"},{"Product Type":"Product Description","Item":"Provides 100 potions free of charge.","Pass":"Provides additional potions."}]

#### Creating a Product Purchase Window UI

  1. Select UI Editor - DefaultGroup - Create Entity - Create UIEmpty to place it, and change its name to MiniShop.
  2. Create a new Item Entity and place it under the MiniShop Entity. Then, use text to make a product purchase window as seen in the following image. [png](16757375937446a32c302638c4bce9c6293df77961900)
  3. In World Shop Viewer, select a product, open the context menu, and choose Copy Item Thumbnail RUID. [png](1669687890427bd427f642355464eaa03d156a1a6c6f7)
  4. Select the image entity to show the product image and paste the product RUID into ImageRUID of SpriteGUIRendererComponent.
  5. Copy the created Item Entity and place it side by side under the MiniShop Entity. [png](1669687708602a247b62ec387466cb86b7290c316f2e4)
  6. Change the name of the copied entity to Pass and add the pass RUID.
  7. [png](CheckboxOff) Disable the Enable property of MiniShop.



#### Creating a Shop Button UI

We're going to create a button for opening and closing the product purchase window. [png](1669181482837083a5716f94f4b9dac17c23994305949)

  1. Place a button of UI Editor - DefaultGroup - ShopOpenBtn.
  2. Look for the shop-shaped sprite and apply it to SpriteGUIRendererComponent - ImageRUID. 
     * ImageRUID: 92a05d93672f65b4f991279cf1f0b4e6
  3. Create a new OpenShopBtn script component and add it to ShopOpenBtn. [png](1668771870564d9e4aa0cc7d84cf78a4d010cf2254125)
  4. Write what you see below to open and close the Minishop by clicking ShopOpenBtn.


    
    
    @Component
    script ShopToggler extends Component
        @ExecSpace("ClientOnly")
        method void OpenShop()
        local Shop = _EntityService:GetEntityByPath("/ui/DefaultGroup/MiniShop")
        local Item = Shop:GetChildByName("Item") 
        local Pass = Shop:GetChildByName("Pass") 
    
        if Shop.Enable == false then
    
            Shop:SetEnable(true)   
    
        else
    
            Shop:SetEnable(false)
    
        end
        end
    end
    

#### Creating a Product Acquisition Confirm Window UI

Let's create a UI that shows the number of potions and passes when a product is successfully purchased.

  1. Go to UI Editor - DefaultGroup - MyPotionInfo to place an image entity.
  2. Place the image and text entities down there and change the name as seen in the following image. [png](166918924041307df0d08c4824221a462c16df2e2b840)



#### Importing Product Information to Purchase Window

  1. Create a new ItemSlot script component and add it to the Item, Pass UI Entities.

  2. Open the ItemSlot component script editor window and add a property.
         
         @Component
         script ItemPurchaseHandler extends Component
         property string ItemID = ""
         property Entity PurchaseBtn = nil
         end
         



    
    
    3. In World Shop Viewer, open the context menu of the product and select Copy ID.
    [png](16691907394815f8bdb41e2224869a012f97b5d142317)
    4. Add the copied ID to the ID of the ItemSlot components of both the item and the pass. 
    [png](1669191109035f825047ab3a2458ab3e37daa4f3c6401)
    5. Select **MyDesk - Create Script - Create EventType** to create a new **ShopOpenEvent**, which will allow you to update the information every time the purchase window is opened.
    [png](166903451819499a0605245bf40c5ad0497ac93cacefb)
    6. Write what you see below to display product information on the product purchase window with a click of the purchase button using `WorldShopService:PromptPurchase()` in the **ItemSlot** component.
    
        ```lua
    @Component
    script ItemPurchaser extends Component
        @ExecSpace("ClientOnly")
        method void PurchaseItem()
        _WorldShopService:PromptPurchase(self.ItemID)
        end
    
        @ExecSpace("ClientOnly")
        method void OnBeginPlay()
                self.PurchaseBtn = self.Entity:GetChildByName("PurchaseBtn")
        --         self.PurchaseBtn:ConnectEvent("ButtonClickEvent", function(event) 
        --             self:PurchaseItem()
        --         end)
        -- [Commented: MLUA requires @EventSender + handler pattern]
        end
    end
    

  7. Add ShopOpenEvent to the Event Handler to enable receiving events with a click of the shop button. Click self, change it to entity, and choose the button entity. [png](1668773199934df13c978c30e49b0989d36024f8a5ce4)
         
         @Component
         script ShopItemRefresher extends Component
         @ExecSpace("ClientOnly")
         method void RefreshShop()
         self._T.ItemName = nil
         self._T.ItemName =  self.Entity:GetChildByName("ItemName").TextComponent
         local SearchResult = _WorldShopService:GetProductAndWait(self.ItemID)
         self._T.ItemName.Text = SearchResult.Name
         end
         
         @EventSender("Self")
         handler HandleShopOpenEvent(any event)
         -- Parameters
         --------------------------------------------------------
         self:RefreshShop()
         end
         end
         



    
    
    #### Offering Products 
    Write what you see below in **MyShopLogic** to provide 100 potions when a successful purchase of a potion is made.
     Use `WorldShopService:SetProcessPurchaseCallback` to provide the product when a purchase is made for it. If the product is successfully offered, the return value should be true, and if not, false.
    
    

@Component script PurchaseRewardHandler extends Component @ExecSpace("ServerOnly") method void OnBeginPlay() _WorldShopService:SetProcessPurchaseCallback(self.ProcessPurchase) end
    
    
    @ExecSpace("ServerOnly")
    method boolean ProcessPurchase(any purchaseInfo)
    local userEntity = _UserService:GetUserEntityByUserId(purchaseInfo.UserId)
    
    if _EntityService:IsValid(userEntity) == false then
        log_error("Invalid user! PurchaseId: " .. purchaseInfo.PurchaseId .. " / " ..
                    "UserId: " .. purchaseInfo.UserId .. " / " ..
                    "ProductId: " .. purchaseInfo.ProductId)
        return false   
    end
    
    if purchaseInfo.ProductId == "Enter ItemID" then     
        userEntity.PlayerReward:GetPotion(100)
    end
    if purchaseInfo.ProductId == "Enter PassID" then
    
        userEntity.PlayerReward:PassCheck()
    
    end
    
    return true
    end
    

end
    
    
    #### Reflecting Product Purchase to UI
    Let's have a purchased product reflected to the owning user.
    1. Create a new **PlayerReward** component and add it to **DefaultPlayer**.
    2. Add a property as follows.
    
        ```lua
    @Component
    script PotionPassState extends Component
        property any PotionValue = "/ui/DefaultGroup/MyPotionInfo/PotionValue"
        @Sync
        property number Potion = 0
        property any PotionValue_2 = "/ui/DefaultGroup/MyPotionInfo/PassValue"
        @Sync
        property boolean HasPass = false
    end
    

  3. Write what you see below to have 100 potions provided when a Potion Item is purchased. 
         
         @Component
         script PlayerPotionDisplay extends Component
         method void GetPoint(number value)
         self.Potion = self.Potion + Value
         end
         
         @ExecSpace("ClientOnly")
         method void OnSyncProperty(string name, any value)
         if self.Entity ~= _UserService.LocalPlayer then
             return
         end
         
         if name == "Potion" then
             self.PotionValue.Text = value
         end
         end
         end
         



    
    
    4. Write what you see below to change the pass ownership UI when a Potion Pass is purchased. Enter the registered pass ID in Pass ID.
    
        ```lua
    @Component
    script PlayerPassVerifier extends Component
        @ExecSpace("ClientOnly")
        method void PassCheck()
        if self.Entity ~= _UserService.LocalPlayer then 
            return 
        end
    
        if _WorldShopService:UserHasPassAndWait(self.Entity.Name, "Pass ID") then 
            self.PassValue.Text = "O"
            self:PassUpdate(true)
        else
            self.PassValue.Text = "x"
            self:PassUpdate(false)
        end
        end
    
        @ExecSpace("ServerOnly")
        method void OnBeginPlay()
        self:PassCheck()
        end
    
        @ExecSpace("ServerOnly")
        method void PassUpdate(boolean value)
        self.HasPass = value
        end
    end
    

  5. Write what you see below to have 15 additional potions offered whenever the pass owner presses Attack.
         
         @Component
         script AttackPotionGrantor extends Component
         @ExecSpace("ServerOnly")
         method void OnBeginPlay()
                     -- Parameters
                     local ActionName = event.ActionName
                     local PlayerEntity = event.PlayerEntity
                     --------------------------------------------------------
                     if self:IsServer() == false then 
                         return 
                     end 
         
                     if self.HasPass == false then 
                         return 
                     end 
         
                     if ActionName ~= "Attack" then 
                         return 
                     end 
         
                     self:GetPotion(15)
         end
         end
         



    
    
    > **Tip**
    > Passes can be purchased only once, so you need to check in advance whether they are available for repurchase.
    > If you press the purchase button of the pass you have already bought, a window appears to inform you that purchase is not allowed.
    > [png](16696875138032c157b741e5a484c82f5119bb21c8722)
    
    > **Tip**
    > Be sure to check that a pass can only be owned by the purchasing user before you release it.
    > We recommend adding a user to the Maker before releasing the pass in the World and testing if the pass can only be owned by the purchaser.
    
    
    ##### Reference Guide
    Users need to be notified before using paid probability-based content as per the Probability Disclosure guideline. Please refer to the [Probability Information Disclosure](/docs/?postId=667) when creating products.
    * [Registering Products](/docs?postId=581)
    * [Product Management](/docs?postId=658)