mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-22 22:30:52 +01:00
Crafting! (NOT DONE YET, DON'T USE IT)
This commit is contained in:
parent
0ad2592f4e
commit
41505f1a08
@ -45,6 +45,9 @@ $nitro-widget-custom-stack-height-height: 220px;
|
|||||||
$nitro-widget-exchange-credit-width: 375px;
|
$nitro-widget-exchange-credit-width: 375px;
|
||||||
$nitro-widget-exchange-credit-height: 150px;
|
$nitro-widget-exchange-credit-height: 150px;
|
||||||
|
|
||||||
|
$nitro-widget-crafting-width: 500px;
|
||||||
|
$nitro-widget-crafting-height: 300px;
|
||||||
|
|
||||||
$chat-history-width: 300px;
|
$chat-history-width: 300px;
|
||||||
$chat-history-height: 300px;
|
$chat-history-height: 300px;
|
||||||
|
|
||||||
|
@ -42,6 +42,10 @@ ul {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cursor-default {
|
||||||
|
cursor: default !important;
|
||||||
|
}
|
||||||
|
|
||||||
.cursor-pointer {
|
.cursor-pointer {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
137
src/components/room/widgets/furniture/FurnitureCraftingView.tsx
Normal file
137
src/components/room/widgets/furniture/FurnitureCraftingView.tsx
Normal file
@ -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(<LayoutGridItem key={ i } itemImage={ ingredientData.iconUrl } className={ (ingredientData.count - (i) <= 0 ? 'opacity-0-5 ' : '') + 'cursor-default' } />);
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
if(objectId === -1) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-widget-crafting" theme="primary-slim">
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText('crafting.title') } onCloseClick={ onClose } />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<Flex grow overflow="hidden" gap={ 2 }>
|
||||||
|
<Flex column fullWidth gap={ 2 }>
|
||||||
|
<Column overflow="hidden" fullHeight>
|
||||||
|
<div className="bg-muted rounded py-1 text-center">{ LocalizeText('crafting.title.products') }</div>
|
||||||
|
<AutoGrid columnCount={ 5 }>
|
||||||
|
{ (recipes.length > 0) && recipes.map((item) => <LayoutGridItem key={ item.name } itemImage={ item.iconUrl } itemActive={ selectedRecipe && selectedRecipe.name === item.name } onClick={ () => selectRecipe(item) } />) }
|
||||||
|
</AutoGrid>
|
||||||
|
</Column>
|
||||||
|
<Column overflow="hidden" fullHeight>
|
||||||
|
<div className="bg-muted rounded py-1 text-center">{ LocalizeText('crafting.title.mixer') }</div>
|
||||||
|
<AutoGrid columnCount={ 5 }>
|
||||||
|
{ (ingredients.length > 0) && ingredients.map((item) => <LayoutGridItem key={ item.name } itemImage={ item.iconUrl } itemCount={ item.count } itemCountMinimum={ 0 } className={ (!item.count ? 'opacity-0-5 ' : '') + 'cursor-default' } />) }
|
||||||
|
</AutoGrid>
|
||||||
|
</Column>
|
||||||
|
</Flex>
|
||||||
|
<Flex column fullWidth gap={ 2 }>
|
||||||
|
{ !selectedRecipe && <Column center fullHeight className="text-black text-center">{ LocalizeText('crafting.info.start') }</Column> }
|
||||||
|
{ selectedRecipe && <>
|
||||||
|
<Column overflow="hidden" fullHeight>
|
||||||
|
<div className="bg-muted rounded py-1 text-center">{ LocalizeText('crafting.current_recipe') }</div>
|
||||||
|
<AutoGrid columnCount={ 5 }>
|
||||||
|
{ (selectedRecipeIngredients.length > 0) && selectedRecipeIngredients.map((item) => renderSelectedRecipeIngredient(item)) }
|
||||||
|
</AutoGrid>
|
||||||
|
</Column>
|
||||||
|
<Flex gap={ 2 } column fullHeight>
|
||||||
|
<Flex gap={ 2 } className="bg-muted rounded" column fullHeight>
|
||||||
|
<div className="py-1 text-center">{ LocalizeText('crafting.result') }</div>
|
||||||
|
<Flex gap={ 1 } center column fullHeight className="pb-1">
|
||||||
|
<Column fullHeight>
|
||||||
|
<img src={ selectedRecipe.iconUrl } />
|
||||||
|
</Column>
|
||||||
|
<div className="text-black">{ selectedRecipe.localizedName }</div>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
<Button variant={ !isOwner || !canCraft ? 'danger' : tryingToCraft ? 'warning' : 'success' } disabled={ !isOwner || !canCraft } onClick={ tryCraft }>
|
||||||
|
{ LocalizeText(!isOwner ? 'crafting.btn.notowner' : !canCraft ? 'crafting.status.recipe.incomplete' : tryingToCraft ? 'generic.cancel' : 'crafting.btn.craft') }
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</> }
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
);
|
||||||
|
}
|
@ -32,6 +32,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nitro-widget-crafting {
|
||||||
|
width: $nitro-widget-crafting-width;
|
||||||
|
height: $nitro-widget-crafting-height;
|
||||||
|
}
|
||||||
|
|
||||||
.nitro-widget-exchange-credit {
|
.nitro-widget-exchange-credit {
|
||||||
width: $nitro-widget-exchange-credit-width;
|
width: $nitro-widget-exchange-credit-width;
|
||||||
height: $nitro-widget-exchange-credit-height;
|
height: $nitro-widget-exchange-credit-height;
|
||||||
|
@ -3,6 +3,7 @@ import { Base } from '../../../../common';
|
|||||||
import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
|
import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView';
|
||||||
import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView';
|
import { FurnitureBackgroundColorView } from './FurnitureBackgroundColorView';
|
||||||
import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView';
|
import { FurnitureBadgeDisplayView } from './FurnitureBadgeDisplayView';
|
||||||
|
import { FurnitureCraftingView } from './FurnitureCraftingView';
|
||||||
import { FurnitureDimmerView } from './FurnitureDimmerView';
|
import { FurnitureDimmerView } from './FurnitureDimmerView';
|
||||||
import { FurnitureExchangeCreditView } from './FurnitureExchangeCreditView';
|
import { FurnitureExchangeCreditView } from './FurnitureExchangeCreditView';
|
||||||
import { FurnitureExternalImageView } from './FurnitureExternalImageView';
|
import { FurnitureExternalImageView } from './FurnitureExternalImageView';
|
||||||
@ -24,6 +25,7 @@ export const FurnitureWidgetsView: FC<{}> = props =>
|
|||||||
<Base fit position="absolute" className="nitro-room-widgets top-0 start-0">
|
<Base fit position="absolute" className="nitro-room-widgets top-0 start-0">
|
||||||
<FurnitureBackgroundColorView />
|
<FurnitureBackgroundColorView />
|
||||||
<FurnitureBadgeDisplayView />
|
<FurnitureBadgeDisplayView />
|
||||||
|
<FurnitureCraftingView />
|
||||||
<FurnitureDimmerView />
|
<FurnitureDimmerView />
|
||||||
<FurnitureExchangeCreditView />
|
<FurnitureExchangeCreditView />
|
||||||
<FurnitureExternalImageView />
|
<FurnitureExternalImageView />
|
||||||
|
@ -17,6 +17,13 @@ const useInventoryFurniState = () =>
|
|||||||
const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility();
|
const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility();
|
||||||
const { isUnseen = null, resetCategory = null } = useInventoryUnseenTracker();
|
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) =>
|
const getWallItemById = (id: number) =>
|
||||||
{
|
{
|
||||||
if(!groupItems || !groupItems.length) return;
|
if(!groupItems || !groupItems.length) return;
|
||||||
@ -285,7 +292,7 @@ const useInventoryFurniState = () =>
|
|||||||
setNeedsUpdate(false);
|
setNeedsUpdate(false);
|
||||||
}, [ isVisible, needsUpdate ]);
|
}, [ 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);
|
export const useInventoryFurni = () => useBetween(useInventoryFurniState);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export * from './useFurnitureBackgroundColorWidget';
|
export * from './useFurnitureBackgroundColorWidget';
|
||||||
export * from './useFurnitureBadgeDisplayWidget';
|
export * from './useFurnitureBadgeDisplayWidget';
|
||||||
export * from './useFurnitureContextMenuWidget';
|
export * from './useFurnitureContextMenuWidget';
|
||||||
|
export * from './useFurnitureCraftingWidget';
|
||||||
export * from './useFurnitureDimmerWidget';
|
export * from './useFurnitureDimmerWidget';
|
||||||
export * from './useFurnitureExchangeWidget';
|
export * from './useFurnitureExchangeWidget';
|
||||||
export * from './useFurnitureExternalImageWidget';
|
export * from './useFurnitureExternalImageWidget';
|
||||||
|
136
src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts
Normal file
136
src/hooks/rooms/widgets/furniture/useFurnitureCraftingWidget.ts
Normal file
@ -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<CraftingRecipeIngredientParser[]>([]);
|
||||||
|
const [ cacheRecipeIngredients, setCacheRecipeIngredients ] = useState<Map<string, CraftingRecipeIngredientParser[]>>(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>(RoomEngineTriggerWidgetEvent.OPEN_WIDGET, event =>
|
||||||
|
{
|
||||||
|
if (event.widget !== RoomWidgetEnum.CRAFTING) return;
|
||||||
|
console.log(event);
|
||||||
|
setObjectId(event.objectId);
|
||||||
|
resetData();
|
||||||
|
SendMessageComposer(new GetCraftableProductsComposer(event.objectId));
|
||||||
|
});
|
||||||
|
|
||||||
|
useMessageEvent<CraftableProductsEvent>(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>(CraftingRecipeEvent, event =>
|
||||||
|
{
|
||||||
|
const parser = event.getParser();
|
||||||
|
setSelectedRecipeIngredients(parser.ingredients);
|
||||||
|
|
||||||
|
const newCache = new Map(cacheRecipeIngredients);
|
||||||
|
newCache.set(selectedRecipe.name, parser.ingredients);
|
||||||
|
setCacheRecipeIngredients(newCache);
|
||||||
|
});
|
||||||
|
|
||||||
|
useMessageEvent<CraftingResultEvent>(CraftingResultEvent, event =>
|
||||||
|
{
|
||||||
|
setSelectedRecipe(null);
|
||||||
|
setSelectedRecipeIngredients([]);
|
||||||
|
|
||||||
|
const parser = event.getParser();
|
||||||
|
|
||||||
|
if (parser.result)
|
||||||
|
{
|
||||||
|
simpleAlert(LocalizeText('crafting.info.result.ok'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useMessageEvent<CraftingRecipesAvailableEvent>(CraftingRecipesAvailableEvent, event =>
|
||||||
|
{
|
||||||
|
});
|
||||||
|
|
||||||
|
return { objectId, recipes, ingredients, selectedRecipe, selectedRecipeIngredients, selectRecipe, onClose };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFurnitureCraftingWidget = useFurnitureCraftingWidgetState;
|
Loading…
Reference in New Issue
Block a user