mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-20 15:36:18 +00:00
🆙 Init V3
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
export * from './useInventoryBadges';
|
||||
export * from './useInventoryBots';
|
||||
export * from './useInventoryFurni';
|
||||
export * from './useInventoryPets';
|
||||
export * from './useInventoryTrade';
|
||||
export * from './useInventoryUnseenTracker';
|
||||
@@ -0,0 +1,152 @@
|
||||
import { BadgeReceivedEvent, BadgesEvent, RequestBadgesComposer, SetActivatedBadgesComposer } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { GetConfigurationValue, SendMessageComposer, UnseenItemCategory } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useSharedVisibility } from '../useSharedVisibility';
|
||||
import { useInventoryUnseenTracker } from './useInventoryUnseenTracker';
|
||||
|
||||
const useInventoryBadgesState = () =>
|
||||
{
|
||||
const [ needsUpdate, setNeedsUpdate ] = useState(true);
|
||||
const [ badgeCodes, setBadgeCodes ] = useState<string[]>([]);
|
||||
const [ badgeIds, setBadgeIds ] = useState<Map<string, number>>(new Map<string, number>());
|
||||
const [ activeBadgeCodes, setActiveBadgeCodes ] = useState<string[]>([]);
|
||||
const [ selectedBadgeCode, setSelectedBadgeCode ] = useState<string>(null);
|
||||
const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility();
|
||||
const { isUnseen = null, resetCategory = null } = useInventoryUnseenTracker();
|
||||
|
||||
const maxBadgeCount = GetConfigurationValue<number>('user.badges.max.slots', 5);
|
||||
const isWearingBadge = (badgeCode: string) => (activeBadgeCodes.indexOf(badgeCode) >= 0);
|
||||
const canWearBadges = () => (activeBadgeCodes.length < maxBadgeCount);
|
||||
|
||||
const toggleBadge = (badgeCode: string) =>
|
||||
{
|
||||
setActiveBadgeCodes(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
const index = newValue.indexOf(badgeCode);
|
||||
|
||||
if(index === -1)
|
||||
{
|
||||
if(!canWearBadges()) return prevValue;
|
||||
|
||||
newValue.push(badgeCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.splice(index, 1);
|
||||
}
|
||||
|
||||
const composer = new SetActivatedBadgesComposer();
|
||||
|
||||
for(let i = 0; i < maxBadgeCount; i++) composer.addActivatedBadge(newValue[i] ?? '');
|
||||
|
||||
SendMessageComposer(composer);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
};
|
||||
|
||||
const getBadgeId = (badgeCode: string) =>
|
||||
{
|
||||
const index = badgeCodes.indexOf(badgeCode);
|
||||
|
||||
if(index === -1) return 0;
|
||||
|
||||
return (badgeIds.get(badgeCode) ?? 0);
|
||||
};
|
||||
|
||||
useMessageEvent<BadgesEvent>(BadgesEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
const badgesToAdd: string[] = [];
|
||||
|
||||
setBadgeIds(prevValue =>
|
||||
{
|
||||
const newValue = new Map(prevValue);
|
||||
|
||||
parser.getAllBadgeCodes().forEach(code =>
|
||||
{
|
||||
const exists = badgeCodes.indexOf(code) >= 0;
|
||||
const badgeId = parser.getBadgeId(code);
|
||||
|
||||
newValue.set(code, badgeId);
|
||||
|
||||
if(exists) return;
|
||||
|
||||
badgesToAdd.push(code);
|
||||
});
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setActiveBadgeCodes(parser.getActiveBadgeCodes());
|
||||
setBadgeCodes(prev => [ ...prev, ...badgesToAdd ]);
|
||||
});
|
||||
|
||||
useMessageEvent<BadgeReceivedEvent>(BadgeReceivedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
const unseen = isUnseen(UnseenItemCategory.BADGE, parser.badgeId);
|
||||
|
||||
setBadgeCodes(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
if(unseen) newValue.unshift(parser.badgeCode);
|
||||
else newValue.push(parser.badgeCode);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setBadgeIds(prevValue =>
|
||||
{
|
||||
const newValue = new Map(prevValue);
|
||||
|
||||
newValue.set(parser.badgeCode, parser.badgeId);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!badgeCodes || !badgeCodes.length) return;
|
||||
|
||||
setSelectedBadgeCode(prevValue =>
|
||||
{
|
||||
let newValue = prevValue;
|
||||
|
||||
if(newValue && (badgeCodes.indexOf(newValue) === -1)) newValue = null;
|
||||
|
||||
if(!newValue) newValue = badgeCodes[0];
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, [ badgeCodes ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
return () =>
|
||||
{
|
||||
resetCategory(UnseenItemCategory.BADGE);
|
||||
};
|
||||
}, [ isVisible, resetCategory ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible || !needsUpdate) return;
|
||||
|
||||
SendMessageComposer(new RequestBadgesComposer());
|
||||
|
||||
setNeedsUpdate(false);
|
||||
}, [ isVisible, needsUpdate ]);
|
||||
|
||||
return { badgeCodes, activeBadgeCodes, selectedBadgeCode, setSelectedBadgeCode, isWearingBadge, canWearBadges, toggleBadge, getBadgeId, activate, deactivate };
|
||||
};
|
||||
|
||||
export const useInventoryBadges = () => useBetween(useInventoryBadgesState);
|
||||
@@ -0,0 +1,158 @@
|
||||
import { BotAddedToInventoryEvent, BotData, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, CreateLinkEvent, GetBotInventoryComposer } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { IBotItem, SendMessageComposer, UnseenItemCategory, cancelRoomObjectPlacement, getPlacingItemId } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useSharedVisibility } from '../useSharedVisibility';
|
||||
import { useInventoryUnseenTracker } from './useInventoryUnseenTracker';
|
||||
|
||||
const useInventoryBotsState = () =>
|
||||
{
|
||||
const [ needsUpdate, setNeedsUpdate ] = useState(true);
|
||||
const [ botItems, setBotItems ] = useState<IBotItem[]>([]);
|
||||
const [ selectedBot, setSelectedBot ] = useState<IBotItem>(null);
|
||||
const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility();
|
||||
const { isUnseen = null, resetCategory = null } = useInventoryUnseenTracker();
|
||||
|
||||
useMessageEvent<BotInventoryMessageEvent>(BotInventoryMessageEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setBotItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
const existingIds = newValue.map(item => item.botData.id);
|
||||
const addedDatas: BotData[] = [];
|
||||
|
||||
for(const botData of parser.items.values()) ((existingIds.indexOf(botData.id) === -1) && addedDatas.push(botData));
|
||||
|
||||
for(const existingId of existingIds)
|
||||
{
|
||||
let remove = true;
|
||||
|
||||
for(const botData of parser.items.values())
|
||||
{
|
||||
if(botData.id === existingId)
|
||||
{
|
||||
remove = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!remove) continue;
|
||||
|
||||
const index = newValue.findIndex(item => (item.botData.id === existingId));
|
||||
const botItem = newValue[index];
|
||||
|
||||
if((index === -1) || !botItem) continue;
|
||||
|
||||
if(getPlacingItemId() === botItem.botData.id)
|
||||
{
|
||||
cancelRoomObjectPlacement();
|
||||
|
||||
CreateLinkEvent('inventory/open');
|
||||
}
|
||||
|
||||
newValue.splice(index, 1);
|
||||
}
|
||||
|
||||
for(const botData of addedDatas)
|
||||
{
|
||||
const botItem = { botData } as IBotItem;
|
||||
const unseen = isUnseen(UnseenItemCategory.BOT, botData.id);
|
||||
|
||||
if(unseen) newValue.unshift(botItem);
|
||||
else newValue.push(botItem);
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<BotAddedToInventoryEvent>(BotAddedToInventoryEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setBotItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
const index = newValue.findIndex(item => (item.botData.id === parser.item.id));
|
||||
|
||||
if(index >= 0) return prevValue;
|
||||
|
||||
const botItem = { botData: parser.item } as IBotItem;
|
||||
const unseen = isUnseen(UnseenItemCategory.BOT, botItem.botData.id);
|
||||
|
||||
if(unseen) newValue.unshift(botItem);
|
||||
else newValue.push(botItem);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<BotRemovedFromInventoryEvent>(BotRemovedFromInventoryEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setBotItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
const index = newValue.findIndex(item => (item.botData.id === parser.itemId));
|
||||
|
||||
if(index === -1) return prevValue;
|
||||
|
||||
newValue.splice(index, 1);
|
||||
|
||||
if(getPlacingItemId() === parser.itemId)
|
||||
{
|
||||
cancelRoomObjectPlacement();
|
||||
|
||||
CreateLinkEvent('inventory/show');
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!botItems || !botItems.length) return;
|
||||
|
||||
setSelectedBot(prevValue =>
|
||||
{
|
||||
let newValue = prevValue;
|
||||
|
||||
if(newValue && (botItems.indexOf(newValue) === -1)) newValue = null;
|
||||
|
||||
if(!newValue) newValue = botItems[0];
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, [ botItems ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
return () =>
|
||||
{
|
||||
resetCategory(UnseenItemCategory.BOT);
|
||||
};
|
||||
}, [ isVisible, resetCategory ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible || !needsUpdate) return;
|
||||
|
||||
SendMessageComposer(new GetBotInventoryComposer());
|
||||
|
||||
setNeedsUpdate(false);
|
||||
}, [ isVisible, needsUpdate ]);
|
||||
|
||||
return { botItems, selectedBot, setSelectedBot, activate, deactivate };
|
||||
};
|
||||
|
||||
export const useInventoryBots = () => useBetween(useInventoryBotsState);
|
||||
@@ -0,0 +1,298 @@
|
||||
import { CreateLinkEvent, FurnitureListAddOrUpdateEvent, FurnitureListComposer, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { CloneObject, DispatchUiEvent, FurnitureItem, GroupItem, SendMessageComposer, UnseenItemCategory, addFurnitureItem, attemptItemPlacement, cancelRoomObjectPlacement, getAllItemIds, getPlacingItemId, mergeFurniFragments } from '../../api';
|
||||
import { InventoryFurniAddedEvent } from '../../events';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useSharedVisibility } from '../useSharedVisibility';
|
||||
import { useInventoryUnseenTracker } from './useInventoryUnseenTracker';
|
||||
|
||||
let furniMsgFragments: Map<number, FurnitureListItemParser>[] = null;
|
||||
|
||||
const useInventoryFurniState = () =>
|
||||
{
|
||||
const [ needsUpdate, setNeedsUpdate ] = useState(true);
|
||||
const [ groupItems, setGroupItems ] = useState<GroupItem[]>([]);
|
||||
const [ selectedItem, setSelectedItem ] = useState<GroupItem>(null);
|
||||
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;
|
||||
|
||||
for(const groupItem of groupItems)
|
||||
{
|
||||
const item = groupItem.getItemById(id);
|
||||
|
||||
if(item && item.isWallItem) return groupItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const getFloorItemById = (id: number) =>
|
||||
{
|
||||
if(!groupItems || !groupItems.length) return;
|
||||
|
||||
for(const groupItem of groupItems)
|
||||
{
|
||||
const item = groupItem.getItemById(id);
|
||||
|
||||
if(item && !item.isWallItem) return groupItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
useMessageEvent<FurnitureListAddOrUpdateEvent>(FurnitureListAddOrUpdateEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setGroupItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
for(const item of parser.items)
|
||||
{
|
||||
let i = 0;
|
||||
let groupItem: GroupItem = null;
|
||||
|
||||
while(i < newValue.length)
|
||||
{
|
||||
const group = newValue[i];
|
||||
|
||||
let j = 0;
|
||||
|
||||
while(j < group.items.length)
|
||||
{
|
||||
const furniture = group.items[j];
|
||||
|
||||
if(furniture.id === item.itemId)
|
||||
{
|
||||
furniture.update(item);
|
||||
|
||||
const newFurniture = [ ...group.items ];
|
||||
|
||||
newFurniture[j] = furniture;
|
||||
|
||||
group.items = newFurniture;
|
||||
|
||||
groupItem = group;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
if(groupItem) break;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if(groupItem)
|
||||
{
|
||||
groupItem.hasUnseenItems = true;
|
||||
|
||||
newValue[i] = CloneObject(groupItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
const furniture = new FurnitureItem(item);
|
||||
|
||||
addFurnitureItem(newValue, furniture, isUnseen(UnseenItemCategory.FURNI, item.itemId));
|
||||
|
||||
DispatchUiEvent(new InventoryFurniAddedEvent(furniture.id, furniture.type, furniture.category));
|
||||
}
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<FurnitureListEvent>(FurnitureListEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!furniMsgFragments) furniMsgFragments = new Array(parser.totalFragments);
|
||||
|
||||
const fragment = mergeFurniFragments(parser.fragment, parser.totalFragments, parser.fragmentNumber, furniMsgFragments);
|
||||
|
||||
if(!fragment) return;
|
||||
|
||||
setGroupItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
const existingIds = getAllItemIds(newValue);
|
||||
|
||||
for(const existingId of existingIds)
|
||||
{
|
||||
if(fragment.get(existingId)) continue;
|
||||
|
||||
let index = 0;
|
||||
|
||||
while(index < newValue.length)
|
||||
{
|
||||
const group = newValue[index];
|
||||
const item = group.remove(existingId);
|
||||
|
||||
if(!item)
|
||||
{
|
||||
index++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(getPlacingItemId() === item.ref)
|
||||
{
|
||||
cancelRoomObjectPlacement();
|
||||
|
||||
if(!attemptItemPlacement(group))
|
||||
{
|
||||
CreateLinkEvent('inventory/show');
|
||||
}
|
||||
}
|
||||
|
||||
if(group.getTotalCount() <= 0)
|
||||
{
|
||||
newValue.splice(index, 1);
|
||||
|
||||
group.dispose();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(const itemId of fragment.keys())
|
||||
{
|
||||
if(existingIds.indexOf(itemId) >= 0) continue;
|
||||
|
||||
const parser = fragment.get(itemId);
|
||||
|
||||
if(!parser) continue;
|
||||
|
||||
const item = new FurnitureItem(parser);
|
||||
|
||||
addFurnitureItem(newValue, item, isUnseen(UnseenItemCategory.FURNI, itemId));
|
||||
|
||||
DispatchUiEvent(new InventoryFurniAddedEvent(item.id, item.type, item.category));
|
||||
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
furniMsgFragments = null;
|
||||
});
|
||||
|
||||
useMessageEvent<FurnitureListInvalidateEvent>(FurnitureListInvalidateEvent, event =>
|
||||
{
|
||||
setNeedsUpdate(true);
|
||||
});
|
||||
|
||||
useMessageEvent<FurnitureListRemovedEvent>(FurnitureListRemovedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setGroupItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
let index = 0;
|
||||
|
||||
while(index < newValue.length)
|
||||
{
|
||||
const group = newValue[index];
|
||||
const item = group.remove(parser.itemId);
|
||||
|
||||
if(!item)
|
||||
{
|
||||
index++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(getPlacingItemId() === item.ref)
|
||||
{
|
||||
cancelRoomObjectPlacement();
|
||||
|
||||
if(!attemptItemPlacement(group)) CreateLinkEvent('inventory/show');
|
||||
}
|
||||
|
||||
if(group.getTotalCount() <= 0)
|
||||
{
|
||||
newValue.splice(index, 1);
|
||||
|
||||
group.dispose();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<FurniturePostItPlacedEvent>(FurniturePostItPlacedEvent, event =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!groupItems || !groupItems.length) return;
|
||||
|
||||
setSelectedItem(prevValue =>
|
||||
{
|
||||
let newValue = prevValue;
|
||||
|
||||
if(newValue && (groupItems.indexOf(newValue) === -1)) newValue = null;
|
||||
|
||||
if(!newValue) newValue = groupItems[0];
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, [ groupItems ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
return () =>
|
||||
{
|
||||
if(resetCategory(UnseenItemCategory.FURNI))
|
||||
{
|
||||
setGroupItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
for(const newGroup of newValue) newGroup.hasUnseenItems = false;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [ isVisible, resetCategory ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible || !needsUpdate) return;
|
||||
|
||||
SendMessageComposer(new FurnitureListComposer());
|
||||
|
||||
setNeedsUpdate(false);
|
||||
}, [ isVisible, needsUpdate ]);
|
||||
|
||||
return { isVisible, groupItems, setGroupItems, selectedItem, setSelectedItem, activate, deactivate, getWallItemById, getFloorItemById, getItemsByType };
|
||||
};
|
||||
|
||||
export const useInventoryFurni = () => useBetween(useInventoryFurniState);
|
||||
@@ -0,0 +1,107 @@
|
||||
import { PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, RequestPetsComposer } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { addSinglePetItem, IPetItem, mergePetFragments, processPetFragment, removePetItemById, SendMessageComposer, UnseenItemCategory } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useSharedVisibility } from '../useSharedVisibility';
|
||||
import { useInventoryUnseenTracker } from './useInventoryUnseenTracker';
|
||||
|
||||
let petMsgFragments: Map<number, PetData>[] = null;
|
||||
|
||||
const useInventoryPetsState = () =>
|
||||
{
|
||||
const [ needsUpdate, setNeedsUpdate ] = useState(true);
|
||||
const [ petItems, setPetItems ] = useState<IPetItem[]>([]);
|
||||
const [ selectedPet, setSelectedPet ] = useState<IPetItem>(null);
|
||||
const { isVisible = false, activate = null, deactivate = null } = useSharedVisibility();
|
||||
const { isUnseen = null, resetCategory = null } = useInventoryUnseenTracker();
|
||||
|
||||
useMessageEvent<PetInventoryEvent>(PetInventoryEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!petMsgFragments) petMsgFragments = new Array(parser.totalFragments);
|
||||
|
||||
const fragment = mergePetFragments(parser.fragment, parser.totalFragments, parser.fragmentNumber, petMsgFragments);
|
||||
|
||||
if(!fragment) return;
|
||||
|
||||
setPetItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
processPetFragment(newValue, fragment, isUnseen);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
petMsgFragments = null;
|
||||
});
|
||||
|
||||
useMessageEvent<PetAddedToInventoryEvent>(PetAddedToInventoryEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setPetItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
addSinglePetItem(parser.pet, newValue, isUnseen(UnseenItemCategory.PET, parser.pet.id));
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<PetRemovedFromInventory>(PetRemovedFromInventory, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setPetItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
removePetItemById(parser.petId, newValue);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!petItems || !petItems.length) return;
|
||||
|
||||
setSelectedPet(prevValue =>
|
||||
{
|
||||
let newValue = prevValue;
|
||||
|
||||
if(newValue && (petItems.indexOf(newValue) === -1)) newValue = null;
|
||||
|
||||
if(!newValue) newValue = petItems[0];
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, [ petItems ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible) return;
|
||||
|
||||
return () =>
|
||||
{
|
||||
resetCategory(UnseenItemCategory.PET);
|
||||
};
|
||||
}, [ isVisible, resetCategory ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!isVisible || !needsUpdate) return;
|
||||
|
||||
SendMessageComposer(new RequestPetsComposer());
|
||||
|
||||
setNeedsUpdate(false);
|
||||
}, [ isVisible, needsUpdate ]);
|
||||
|
||||
return { petItems, selectedPet, setSelectedPet, activate, deactivate };
|
||||
};
|
||||
|
||||
export const useInventoryPets = () => useBetween(useInventoryPetsState);
|
||||
@@ -0,0 +1,288 @@
|
||||
import { AdvancedMap, GetSessionDataManager, TradingAcceptComposer, TradingAcceptEvent, TradingCancelComposer, TradingCloseComposer, TradingCloseEvent, TradingCloseParser, TradingCompletedEvent, TradingConfirmationComposer, TradingConfirmationEvent, TradingListItemEvent, TradingListItemRemoveComposer, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingUnacceptComposer, TradingYouAreNotAllowedEvent } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { CloneObject, GetRoomSession, GroupItem, LocalizeText, SendMessageComposer, TradeState, TradeUserData, TradingNotificationType, parseTradeItems } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useNotification } from '../notification';
|
||||
import { useInventoryFurni } from './useInventoryFurni';
|
||||
|
||||
const useInventoryTradeState = () =>
|
||||
{
|
||||
const [ ownUser, setOwnUser ] = useState<TradeUserData>(null);
|
||||
const [ otherUser, setOtherUser ] = useState<TradeUserData>(null);
|
||||
const [ tradeState, setTradeState ] = useState(TradeState.TRADING_STATE_READY);
|
||||
const { groupItems = [], setGroupItems = null, activate = null, deactivate = null } = useInventoryFurni();
|
||||
const { simpleAlert = null, showTradeAlert = null } = useNotification();
|
||||
const isTrading = (tradeState >= TradeState.TRADING_STATE_RUNNING);
|
||||
|
||||
const progressTrade = () =>
|
||||
{
|
||||
switch(tradeState)
|
||||
{
|
||||
case TradeState.TRADING_STATE_RUNNING:
|
||||
if(!otherUser.itemCount && !ownUser.accepts)
|
||||
{
|
||||
simpleAlert(LocalizeText('inventory.trading.warning.other_not_offering'), null, null, null);
|
||||
}
|
||||
|
||||
if(ownUser.accepts)
|
||||
{
|
||||
SendMessageComposer(new TradingUnacceptComposer());
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessageComposer(new TradingAcceptComposer());
|
||||
}
|
||||
return;
|
||||
case TradeState.TRADING_STATE_CONFIRMING:
|
||||
SendMessageComposer(new TradingConfirmationComposer());
|
||||
|
||||
setTradeState(TradeState.TRADING_STATE_CONFIRMED);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
const removeItem = (group: GroupItem) =>
|
||||
{
|
||||
const item = group.getLastItem();
|
||||
|
||||
if(!item) return;
|
||||
|
||||
SendMessageComposer(new TradingListItemRemoveComposer(item.id));
|
||||
};
|
||||
|
||||
const stopTrading = () =>
|
||||
{
|
||||
if(!isTrading) return;
|
||||
|
||||
switch(tradeState)
|
||||
{
|
||||
case TradeState.TRADING_STATE_RUNNING:
|
||||
SendMessageComposer(new TradingCloseComposer());
|
||||
return;
|
||||
default:
|
||||
SendMessageComposer(new TradingCancelComposer());
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
useMessageEvent<TradingAcceptEvent>(TradingAcceptEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(!ownUser || !otherUser) return;
|
||||
|
||||
if(ownUser.userId === parser.userID)
|
||||
{
|
||||
setOwnUser(prevValue =>
|
||||
{
|
||||
const newValue = CloneObject(prevValue);
|
||||
|
||||
newValue.accepts = parser.userAccepts;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
|
||||
else if(otherUser.userId === parser.userID)
|
||||
{
|
||||
setOtherUser(prevValue =>
|
||||
{
|
||||
const newValue = CloneObject(prevValue);
|
||||
|
||||
newValue.accepts = parser.userAccepts;
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
useMessageEvent<TradingCloseEvent>(TradingCloseEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
if(parser.reason === TradingCloseParser.ERROR_WHILE_COMMIT)
|
||||
{
|
||||
showTradeAlert(TradingNotificationType.ERROR_WHILE_COMMIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ownUser && (parser.userID !== ownUser.userId))
|
||||
{
|
||||
showTradeAlert(TradingNotificationType.THEY_CANCELLED);
|
||||
}
|
||||
}
|
||||
|
||||
setOwnUser(null);
|
||||
setOtherUser(null);
|
||||
setTradeState(TradeState.TRADING_STATE_READY);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingCompletedEvent>(TradingCompletedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setOwnUser(null);
|
||||
setOtherUser(null);
|
||||
setTradeState(TradeState.TRADING_STATE_READY);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingConfirmationEvent>(TradingConfirmationEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setTradeState(TradeState.TRADING_STATE_COUNTDOWN);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingListItemEvent>(TradingListItemEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
const firstUserItems = parseTradeItems(parser.firstUserItemArray);
|
||||
const secondUserItems = parseTradeItems(parser.secondUserItemArray);
|
||||
|
||||
setOwnUser(prevValue =>
|
||||
{
|
||||
const newValue = CloneObject(prevValue);
|
||||
|
||||
if(newValue.userId === parser.firstUserID)
|
||||
{
|
||||
newValue.creditsCount = parser.firstUserNumCredits;
|
||||
newValue.itemCount = parser.firstUserNumItems;
|
||||
newValue.userItems = firstUserItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.creditsCount = parser.secondUserNumCredits;
|
||||
newValue.itemCount = parser.secondUserNumItems;
|
||||
newValue.userItems = secondUserItems;
|
||||
}
|
||||
|
||||
const tradeIds: number[] = [];
|
||||
|
||||
for(const groupItem of newValue.userItems.getValues())
|
||||
{
|
||||
let i = 0;
|
||||
|
||||
while(i < groupItem.getTotalCount())
|
||||
{
|
||||
const item = groupItem.getItemByIndex(i);
|
||||
|
||||
if(item) tradeIds.push(item.ref);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
setGroupItems(prevValue =>
|
||||
{
|
||||
const newValue = [ ...prevValue ];
|
||||
|
||||
for(const groupItem of newValue) groupItem.lockItemIds(tradeIds);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
setOtherUser(prevValue =>
|
||||
{
|
||||
const newValue = CloneObject(prevValue);
|
||||
|
||||
if(newValue.userId === parser.firstUserID)
|
||||
{
|
||||
newValue.creditsCount = parser.firstUserNumCredits;
|
||||
newValue.itemCount = parser.firstUserNumItems;
|
||||
newValue.userItems = firstUserItems;
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue.creditsCount = parser.secondUserNumCredits;
|
||||
newValue.itemCount = parser.secondUserNumItems;
|
||||
newValue.userItems = secondUserItems;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
useMessageEvent<TradingNotOpenEvent>(TradingNotOpenEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
});
|
||||
|
||||
useMessageEvent<TradingOpenEvent>(TradingOpenEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
const firstUser = new TradeUserData();
|
||||
const firstUserData = GetRoomSession().userDataManager.getUserData(parser.userID);
|
||||
|
||||
firstUser.userItems = new AdvancedMap();
|
||||
|
||||
const secondUser = new TradeUserData();
|
||||
const secondUserData = GetRoomSession().userDataManager.getUserData(parser.otherUserID);
|
||||
|
||||
secondUser.userItems = new AdvancedMap();
|
||||
|
||||
if(firstUserData.webID === GetSessionDataManager().userId)
|
||||
{
|
||||
firstUser.userId = firstUserData.webID;
|
||||
firstUser.userName = firstUserData.name;
|
||||
firstUser.canTrade = parser.userCanTrade;
|
||||
|
||||
secondUser.userId = secondUserData.webID;
|
||||
secondUser.userName = secondUserData.name;
|
||||
secondUser.canTrade = parser.otherUserCanTrade;
|
||||
}
|
||||
|
||||
else if(secondUserData.webID === GetSessionDataManager().userId)
|
||||
{
|
||||
firstUser.userId = secondUserData.webID;
|
||||
firstUser.userName = secondUserData.name;
|
||||
firstUser.canTrade = parser.otherUserCanTrade;
|
||||
|
||||
secondUser.userId = firstUserData.webID;
|
||||
secondUser.userName = firstUserData.name;
|
||||
secondUser.canTrade = parser.userCanTrade;
|
||||
}
|
||||
|
||||
setOwnUser(firstUser);
|
||||
setOtherUser(secondUser);
|
||||
setTradeState(TradeState.TRADING_STATE_RUNNING);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingOpenFailedEvent>(TradingOpenFailedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
showTradeAlert(parser.reason, parser.otherUserName);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingOtherNotAllowedEvent>(TradingOtherNotAllowedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
showTradeAlert(TradingNotificationType.THEY_NOT_ALLOWED);
|
||||
});
|
||||
|
||||
useMessageEvent<TradingYouAreNotAllowedEvent>(TradingYouAreNotAllowedEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
showTradeAlert(TradingNotificationType.YOU_NOT_ALLOWED);
|
||||
});
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(tradeState === TradeState.TRADING_STATE_READY) return;
|
||||
|
||||
const id = activate();
|
||||
|
||||
return () => deactivate(id);
|
||||
}, [ tradeState, activate, deactivate ]);
|
||||
|
||||
return { ownUser, otherUser, tradeState, setTradeState, isTrading, groupItems, progressTrade, removeItem, stopTrading };
|
||||
};
|
||||
|
||||
export const useInventoryTrade = () => useBetween(useInventoryTradeState);
|
||||
@@ -0,0 +1,132 @@
|
||||
import { UnseenItemsEvent, UnseenResetCategoryComposer, UnseenResetItemsComposer } from '@nitrots/nitro-renderer';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { SendMessageComposer } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
|
||||
const sendResetCategoryMessage = (category: number) => SendMessageComposer(new UnseenResetCategoryComposer(category));
|
||||
const sendResetItemsMessage = (category: number, itemIds: number[]) => SendMessageComposer(new UnseenResetItemsComposer(category, ...itemIds));
|
||||
|
||||
const useInventoryUnseenTrackerState = () =>
|
||||
{
|
||||
const [ unseenItems, setUnseenItems ] = useState<Map<number, number[]>>(new Map());
|
||||
|
||||
const getCount = useCallback((category: number) => (unseenItems.get(category)?.length || 0), [ unseenItems ]);
|
||||
|
||||
const getFullCount = useMemo(() =>
|
||||
{
|
||||
let count = 0;
|
||||
|
||||
for(const key of unseenItems.keys()) count += getCount(key);
|
||||
|
||||
return count;
|
||||
}, [ unseenItems, getCount ]);
|
||||
|
||||
const resetCategory = useCallback((category: number) =>
|
||||
{
|
||||
let didReset = true;
|
||||
|
||||
setUnseenItems(prevValue =>
|
||||
{
|
||||
if(!prevValue.has(category))
|
||||
{
|
||||
didReset = false;
|
||||
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
const newValue = new Map(prevValue);
|
||||
|
||||
newValue.delete(category);
|
||||
|
||||
sendResetCategoryMessage(category);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return didReset;
|
||||
}, []);
|
||||
|
||||
const resetItems = useCallback((category: number, itemIds: number[]) =>
|
||||
{
|
||||
let didReset = true;
|
||||
|
||||
setUnseenItems(prevValue =>
|
||||
{
|
||||
if(!prevValue.has(category))
|
||||
{
|
||||
didReset = false;
|
||||
|
||||
return prevValue;
|
||||
}
|
||||
|
||||
const newValue = new Map(prevValue);
|
||||
const existing = newValue.get(category);
|
||||
|
||||
if(existing) for(const itemId of itemIds) existing.splice(existing.indexOf(itemId), 1);
|
||||
|
||||
sendResetItemsMessage(category, itemIds);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
|
||||
return didReset;
|
||||
}, []);
|
||||
|
||||
const isUnseen = useCallback((category: number, itemId: number) =>
|
||||
{
|
||||
if(!unseenItems.has(category)) return false;
|
||||
|
||||
const items = unseenItems.get(category);
|
||||
|
||||
return (items.indexOf(itemId) >= 0);
|
||||
}, [ unseenItems ]);
|
||||
|
||||
const removeUnseen = useCallback((category: number, itemId: number) =>
|
||||
{
|
||||
setUnseenItems(prevValue =>
|
||||
{
|
||||
if(!prevValue.has(category)) return prevValue;
|
||||
|
||||
const newValue = new Map(prevValue);
|
||||
const items = newValue.get(category);
|
||||
const index = items.indexOf(itemId);
|
||||
|
||||
if(index >= 0) items.splice(index, 1);
|
||||
|
||||
return newValue;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useMessageEvent<UnseenItemsEvent>(UnseenItemsEvent, event =>
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
setUnseenItems(prevValue =>
|
||||
{
|
||||
const newValue = new Map(prevValue);
|
||||
|
||||
for(const category of parser.categories)
|
||||
{
|
||||
let existing = newValue.get(category);
|
||||
|
||||
if(!existing)
|
||||
{
|
||||
existing = [];
|
||||
|
||||
newValue.set(category, existing);
|
||||
}
|
||||
|
||||
const itemIds = parser.getItemsByCategory(category);
|
||||
|
||||
for(const itemId of itemIds) ((existing.indexOf(itemId) === -1) && existing.push(itemId));
|
||||
}
|
||||
|
||||
return newValue;
|
||||
});
|
||||
});
|
||||
|
||||
return { getCount, getFullCount, resetCategory, resetItems, isUnseen, removeUnseen };
|
||||
};
|
||||
|
||||
export const useInventoryUnseenTracker = () => useBetween(useInventoryUnseenTrackerState);
|
||||
Reference in New Issue
Block a user