From 41505f1a086921082fa624a05231f8d4e25abe6e Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Tue, 20 Sep 2022 17:32:47 -0300 Subject: [PATCH] Crafting! (NOT DONE YET, DON'T USE IT) --- src/App.scss | 3 + src/assets/styles/utils.scss | 4 + .../furniture/FurnitureCraftingView.tsx | 137 ++++++++++++++++++ .../widgets/furniture/FurnitureWidgets.scss | 5 + .../furniture/FurnitureWidgetsView.tsx | 2 + src/hooks/inventory/useInventoryFurni.ts | 9 +- src/hooks/rooms/widgets/furniture/index.ts | 1 + .../furniture/useFurnitureCraftingWidget.ts | 136 +++++++++++++++++ 8 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 src/components/room/widgets/furniture/FurnitureCraftingView.tsx create mode 100644 src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts diff --git a/src/App.scss b/src/App.scss index 9a3bd885..2000adec 100644 --- a/src/App.scss +++ b/src/App.scss @@ -45,6 +45,9 @@ $nitro-widget-custom-stack-height-height: 220px; $nitro-widget-exchange-credit-width: 375px; $nitro-widget-exchange-credit-height: 150px; +$nitro-widget-crafting-width: 500px; +$nitro-widget-crafting-height: 300px; + $chat-history-width: 300px; $chat-history-height: 300px; diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index f8710058..d32a832a 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -42,6 +42,10 @@ ul { } } +.cursor-default { + cursor: default !important; +} + .cursor-pointer { cursor: pointer; } diff --git a/src/components/room/widgets/furniture/FurnitureCraftingView.tsx b/src/components/room/widgets/furniture/FurnitureCraftingView.tsx new file mode 100644 index 00000000..183b7ccd --- /dev/null +++ b/src/components/room/widgets/furniture/FurnitureCraftingView.tsx @@ -0,0 +1,137 @@ +import { CraftComposer, CraftingRecipeIngredientParser, RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetRoomEngine, IsOwnerOfFurniture, LocalizeText, SendMessageComposer } from '../../../../api'; +import { AutoGrid, Button, Column, Flex, LayoutGridItem, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common'; +import { useFurnitureCraftingWidget, useInventoryFurni, useRoom } from '../../../../hooks'; + +export const FurnitureCraftingView: FC<{}> = props => +{ + const { objectId = -1, recipes = [], ingredients = [], selectedRecipe = null, selectedRecipeIngredients = null, selectRecipe = null, onClose = null } = useFurnitureCraftingWidget(); + const { activate, deactivate } = useInventoryFurni(); + const { roomSession = null } = useRoom(); + + const [ craftCounter, setCraftCounter ] = useState(0); + const [ tryingToCraft, setTryingToCraft ] = useState(false); + const [ craftInterval, setCraftInterval ] = useState(null); + + const isOwner = useMemo(() => + { + const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); + return IsOwnerOfFurniture(roomObject); + }, [ objectId, roomSession.roomId ]); + + const canCraft = useMemo(() => + { + for (const ingredient of selectedRecipeIngredients) + { + const ingredientData = ingredients.find((i) => i.name === ingredient.itemName); + + if (ingredientData.count < ingredient.count) return false; + } + + return true; + }, [ ingredients, selectedRecipeIngredients ]); + + const cancelCraft = () => + { + setTryingToCraft(false); + setCraftCounter(0); + clearInterval(craftInterval); + }; + + const tryCraft = () => + { + if (tryingToCraft) + { + cancelCraft(); + return; + } + + setCraftCounter(5); + setTryingToCraft(true); + setCraftInterval(setInterval(() => setCraftCounter(v => v - 1), 1000)); + }; + + useEffect(() => + { + if (craftCounter <= 0 && tryingToCraft) + { + clearInterval(craftInterval); + setCraftInterval(null); + setTryingToCraft(false); + craft(); + } + }, [ craftCounter ]); + + const craft = useCallback(() => + { + if (!selectedRecipe) return; + + SendMessageComposer(new CraftComposer(objectId, selectedRecipe.name)); + }, [ objectId, selectedRecipe ]); + + const renderSelectedRecipeIngredient = (ingredient: CraftingRecipeIngredientParser) => + { + const ingredientData = ingredients.find((i) => i.name === ingredient.itemName); + + const elements = []; + + for (let i = 0; i < ingredient.count; i++) + { + elements.push(); + } + + return elements; + }; + + if(objectId === -1) return null; + + return ( + + + + + + +
{ LocalizeText('crafting.title.products') }
+ + { (recipes.length > 0) && recipes.map((item) => selectRecipe(item) } />) } + +
+ +
{ LocalizeText('crafting.title.mixer') }
+ + { (ingredients.length > 0) && ingredients.map((item) => ) } + +
+
+ + { !selectedRecipe && { LocalizeText('crafting.info.start') } } + { selectedRecipe && <> + +
{ LocalizeText('crafting.current_recipe') }
+ + { (selectedRecipeIngredients.length > 0) && selectedRecipeIngredients.map((item) => renderSelectedRecipeIngredient(item)) } + +
+ + +
{ LocalizeText('crafting.result') }
+ + + + +
{ selectedRecipe.localizedName }
+
+
+ +
+ } +
+
+
+
+ ); +} diff --git a/src/components/room/widgets/furniture/FurnitureWidgets.scss b/src/components/room/widgets/furniture/FurnitureWidgets.scss index e7d8bdf2..42a666cd 100644 --- a/src/components/room/widgets/furniture/FurnitureWidgets.scss +++ b/src/components/room/widgets/furniture/FurnitureWidgets.scss @@ -32,6 +32,11 @@ } } +.nitro-widget-crafting { + width: $nitro-widget-crafting-width; + height: $nitro-widget-crafting-height; +} + .nitro-widget-exchange-credit { width: $nitro-widget-exchange-credit-width; height: $nitro-widget-exchange-credit-height; diff --git a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx index 207d934a..dda72172 100644 --- a/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/components/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -3,6 +3,7 @@ import { Base } from '../../../../common'; import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView'; import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView'; import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView'; +import { FurnitureCraftingView } from './FurnitureCraftingView'; import { FurnitureDimmerView } from './FurnitureDimmerView'; import { FurnitureExchangeCreditView } from './FurnitureExchangeCreditView'; import { FurnitureExternalImageView } from './FurnitureExternalImageView'; @@ -24,6 +25,7 @@ export const FurnitureWidgetsView: FC<{}> = props => + diff --git a/src/hooks/inventory/useInventoryFurni.ts b/src/hooks/inventory/useInventoryFurni.ts index 47b1e989..d57bd8df 100644 --- a/src/hooks/inventory/useInventoryFurni.ts +++ b/src/hooks/inventory/useInventoryFurni.ts @@ -17,6 +17,13 @@ const useInventoryFurniState = () => const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility(); const { isUnseen = null, resetCategory = null } = useInventoryUnseenTracker(); + const getItemsByType = (type: number) => + { + if(!groupItems || !groupItems.length) return; + + return groupItems.filter((i) => i.type === type); + } + const getWallItemById = (id: number) => { if(!groupItems || !groupItems.length) return; @@ -285,7 +292,7 @@ const useInventoryFurniState = () => setNeedsUpdate(false); }, [ isVisible, needsUpdate ]); - return { isVisible, groupItems, setGroupItems, selectedItem, setSelectedItem, activate, deactivate, getWallItemById, getFloorItemById }; + return { isVisible, groupItems, setGroupItems, selectedItem, setSelectedItem, activate, deactivate, getWallItemById, getFloorItemById, getItemsByType }; } export const useInventoryFurni = () => useBetween(useInventoryFurniState); diff --git a/src/hooks/rooms/widgets/furniture/index.ts b/src/hooks/rooms/widgets/furniture/index.ts index 58a31058..f4d96675 100644 --- a/src/hooks/rooms/widgets/furniture/index.ts +++ b/src/hooks/rooms/widgets/furniture/index.ts @@ -1,6 +1,7 @@ export * from './useFurnitureBackgroundColorWidget'; export * from './useFurnitureBadgeDisplayWidget'; export * from './useFurnitureContextMenuWidget'; +export * from './useFurnitureCraftingWidget'; export * from './useFurnitureDimmerWidget'; export * from './useFurnitureExchangeWidget'; export * from './useFurnitureExternalImageWidget'; diff --git a/src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts b/src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts new file mode 100644 index 00000000..9826dfa6 --- /dev/null +++ b/src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts @@ -0,0 +1,136 @@ +import { CraftableProductsEvent, CraftingRecipeEvent, CraftingRecipeIngredientParser, CraftingRecipesAvailableEvent, CraftingResultEvent, GetCraftableProductsComposer, GetCraftingRecipeComposer, RoomEngineTriggerWidgetEvent, RoomWidgetEnum } from '@nitrots/nitro-renderer'; +import { useCallback, useState } from 'react'; +import { GetRoomEngine, LocalizeText, SendMessageComposer } from '../../../../api'; +import { useMessageEvent, useRoomEngineEvent } from '../../../events'; +import { useInventoryFurni } from '../../../inventory'; +import { useNotification } from './../../../notification/useNotification'; + +const useFurnitureCraftingWidgetState = () => +{ + const { getItemsByType } = useInventoryFurni(); + const { simpleAlert } = useNotification(); + + const [ objectId, setObjectId ] = useState(-1); + const [ recipes, setRecipes ] = useState<{ name: string, localizedName: string, iconUrl: string }[]>([]); + const [ ingredients, setIngredients ] = useState<{ name: string, iconUrl: string, count: number }[]>([]); + const [ selectedRecipe, setSelectedRecipe ] = useState<{ name: string, localizedName: string, iconUrl: string }>(null); + const [ selectedRecipeIngredients, setSelectedRecipeIngredients ] = useState([]); + const [ cacheRecipeIngredients, setCacheRecipeIngredients ] = useState>(new Map()); + + const resetData = () => + { + setRecipes([]); + setIngredients([]); + setSelectedRecipe(null); + setSelectedRecipeIngredients([]); + setCacheRecipeIngredients(new Map()); + }; + + const onClose = () => + { + setObjectId(-1); + resetData(); + }; + + const selectRecipe = useCallback((recipe: { name: string, localizedName: string, iconUrl: string }) => + { + setSelectedRecipeIngredients([]); + setSelectedRecipe(recipe); + + const cache = cacheRecipeIngredients.get(recipe.name); + + if (cache) + setSelectedRecipeIngredients(cache); + else + SendMessageComposer(new GetCraftingRecipeComposer(recipe.name)); + }, [ cacheRecipeIngredients ]); + + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.OPEN_WIDGET, event => + { + if (event.widget !== RoomWidgetEnum.CRAFTING) return; + console.log(event); + setObjectId(event.objectId); + resetData(); + SendMessageComposer(new GetCraftableProductsComposer(event.objectId)); + }); + + useMessageEvent(CraftableProductsEvent, event => + { + const parser = event.getParser(); + + if (!parser.isActive()) + { + setObjectId(-1); + return; + } + + const recipesToSet = []; + + for(const recipe of parser.recipes) + { + //@ts-ignore + const itemId = GetRoomEngine().roomContentLoader._activeObjectTypeIds.get(recipe.itemName); + const iconUrl = GetRoomEngine().getFurnitureFloorIconUrl(itemId); + recipesToSet.push({ + name: recipe.itemName, + localizedName: LocalizeText('roomItem.name.' + itemId), + iconUrl + }); + } + + setRecipes(recipesToSet); + + const ingredientsToSet = []; + + for(const ingredient of parser.ingredients) + { + //@ts-ignore + const itemId = GetRoomEngine().roomContentLoader._activeObjectTypeIds.get(ingredient); + const iconUrl = GetRoomEngine().getFurnitureFloorIconUrl(itemId); + + const inventoryItems = getItemsByType(itemId); + let amountAvailable = 0; + + for (const inventoryItem of inventoryItems) amountAvailable += inventoryItem.items.length; + + ingredientsToSet.push({ + name: ingredient, + iconUrl, + count: amountAvailable + }); + } + + setIngredients(ingredientsToSet); + }); + + useMessageEvent(CraftingRecipeEvent, event => + { + const parser = event.getParser(); + setSelectedRecipeIngredients(parser.ingredients); + + const newCache = new Map(cacheRecipeIngredients); + newCache.set(selectedRecipe.name, parser.ingredients); + setCacheRecipeIngredients(newCache); + }); + + useMessageEvent(CraftingResultEvent, event => + { + setSelectedRecipe(null); + setSelectedRecipeIngredients([]); + + const parser = event.getParser(); + + if (parser.result) + { + simpleAlert(LocalizeText('crafting.info.result.ok')); + } + }); + + useMessageEvent(CraftingRecipesAvailableEvent, event => + { + }); + + return { objectId, recipes, ingredients, selectedRecipe, selectedRecipeIngredients, selectRecipe, onClose }; +} + +export const useFurnitureCraftingWidget = useFurnitureCraftingWidgetState;