🆙 Init V3

This commit is contained in:
DuckieTM
2026-01-31 09:10:52 +01:00
commit 7feb10ab15
1733 changed files with 53405 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
export * from './useInventoryBadges';
export * from './useInventoryBots';
export * from './useInventoryFurni';
export * from './useInventoryPets';
export * from './useInventoryTrade';
export * from './useInventoryUnseenTracker';
+152
View File
@@ -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);
+158
View File
@@ -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);
+298
View File
@@ -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);
+107
View File
@@ -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);
+288
View File
@@ -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);