diff --git a/.gitignore b/.gitignore index b9912a25..22b21346 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ Makefile *.vcxproj.* *.xcodeproj/ *.xcworkspace +*.log # IDE files .idea/ diff --git a/CHANGES.md b/CHANGES.md index 618ec747..4088ac17 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,7 +1,8 @@ ## change log ### HEAD -- Updated to Steamworks SDK v1.46. +- Updated to Steamworks SDK v1.49. +- Added SteamInventory interface. - Added `SteamUserCallback.onAuthSessionTicket()`. (#83) ### [1.8.0] diff --git a/build-natives/build-win.lua b/build-natives/build-win.lua index 66e299b8..7a4046df 100644 --- a/build-natives/build-win.lua +++ b/build-natives/build-win.lua @@ -3,7 +3,7 @@ solution "steamworks4j" platforms { "x32", "x64" } -- Premake 5.0.0 alpha 11 : SDK version needs to be specified for VS2017 - systemversion("10.0.14393.0") + systemversion("10.0.18362.0") includedirs { "../java-wrapper/src/main/native/include/jni", diff --git a/java-wrapper/pom.xml b/java-wrapper/pom.xml index 7a407bb4..f4e7405e 100644 --- a/java-wrapper/pom.xml +++ b/java-wrapper/pom.xml @@ -142,8 +142,8 @@ maven-compiler-plugin 3.0 - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamAPI.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamAPI.java index 653f3237..8d5d6ec1 100644 --- a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamAPI.java +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamAPI.java @@ -135,6 +135,10 @@ static boolean isIsNativeAPILoaded() { return (intp) SteamHTTP(); */ + static native long getSteamInventoryPointer(); /* + return (intp) SteamInventory(); + */ + static native long getSteamMatchmakingPointer(); /* return (intp) SteamMatchmaking(); */ diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventory.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventory.java new file mode 100644 index 00000000..0d7de379 --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventory.java @@ -0,0 +1,711 @@ +package com.codedisaster.steamworks; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class SteamInventory extends SteamInterface { + public enum SteamItemFlags { + NoTrade(1 << 0), + Removed(1 << 8), + Consumed(1 << 9); + + private final int bits; + + SteamItemFlags(int bits) { + this.bits = bits; + } + + public static boolean isSet(SteamInventory.SteamItemFlags value, int bitMask) { + return (value.bits & bitMask) == value.bits; + } + } + + public static class SteamItemDetails { + private long itemId; + private int itemDefinition; + private short quantity; + private short flags; + + public SteamItemInstanceId getItemId() { + return new SteamItemInstanceId(itemId); + } + + public int getItemDefinition() { + return itemDefinition; + } + + public short getQuantity() { + return quantity; + } + + public short getFlags() { + return flags; + } + } + + public static class SteamInventoryValue { + private String value; + + public String getValue() { + return value; + } + } + + public SteamInventory(SteamInventoryCallback callback) { + super(SteamAPI.getSteamInventoryPointer(), createCallback(new SteamInventoryCallbackAdapter(callback))); + } + + public SteamResult getResultStatus(SteamInventoryHandle inventory) { + return SteamResult.byValue(getResultStatus(pointer, inventory.handle)); + } + + public int getResultItemsLength(SteamInventoryHandle inventory) { + return getResultItemsLength(pointer, inventory.handle); + } + + public boolean getResultItems(SteamInventoryHandle inventory, List itemDetails) { + final int itemCount = getResultItemsLength(pointer, inventory.handle); + if(itemCount > 0) { + SteamItemDetails[] steamItemDetailsArray = new SteamItemDetails[itemCount]; + + for(int i = 0; i < itemCount; i++) { + steamItemDetailsArray[i] = new SteamItemDetails(); + } + + final boolean result = getResultItems(pointer, inventory.handle, steamItemDetailsArray); + + if(result) { + itemDetails.addAll(Arrays.stream(steamItemDetailsArray).collect(Collectors.toList())); + } + + return result; + } + + return false; + } + + public String getResultItemPropertyKeys(SteamInventoryHandle inventory, int itemIndex) { + return getResultItemPropertyKeys(pointer, inventory.handle, itemIndex); + } + + public boolean getResultItemProperty(SteamInventoryHandle inventory, int itemIndex, String propertyName, List values) { + SteamInventoryValue steamValue = new SteamInventoryValue(); + + final boolean result = getResultItemProperty(pointer, inventory.handle, itemIndex, propertyName, steamValue); + + values.add(steamValue.getValue()); + + return result; + } + + public int getResultTimestamp(SteamInventoryHandle inventory) { + return getResultTimestamp(pointer, inventory.handle); + } + + public boolean checkResultSteamID(SteamInventoryHandle inventory, SteamID steamIDExpected) { + return checkResultSteamID(pointer, inventory.handle, steamIDExpected.handle); + } + + public void destroyResult(SteamInventoryHandle inventory) { + destroyResult(pointer, inventory.handle); + } + + public boolean getAllItems(List inventories) { + int[] tempIntArray = new int[1]; + + final boolean result = getAllItems(pointer, tempIntArray); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean getItemsByID(List inventories, List instanceIDs) { + int[] tempIntArray = new int[1]; + + final boolean result = getItemsByID(pointer, tempIntArray, instanceIDs.stream().mapToLong(steamItemInstanceId -> steamItemInstanceId.handle).toArray(), instanceIDs.size()); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public int getSizeNeededForResultSerialization(SteamInventoryHandle inventory) { + return serializeResultSize(pointer, inventory.handle); + } + + public boolean serializeResult(SteamInventoryHandle inventory, ByteBuffer outBuffer) throws SteamException { + if (!outBuffer.isDirect()) { + throw new SteamException("Direct buffer required!"); + } + + return serializeResult(pointer, inventory.handle, outBuffer, outBuffer.position(), outBuffer.remaining()); + } + + // STEAM_BUFFER_COUNT(punOutBufferSize) void *pBuffer + public boolean deserializeResult(List inventories, ByteBuffer buffer) { + int[] tempIntArray = new int[1]; + + final boolean result = deserializeResult(pointer, tempIntArray, buffer, buffer.position(), buffer.remaining(), false); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + // STEAM_ARRAY_COUNT(unArrayLength) int[] pArrayItemDefs, STEAM_ARRAY_COUNT(unArrayLength) + public boolean generateItems(List inventories, int[] arrayItemDefs, int[] arrayQuantity) { + if(arrayItemDefs.length != arrayQuantity.length) { + throw new IllegalArgumentException("The length of arrayItemDefs and arrayQuantity must match!"); + } + + int[] tempIntArray = new int[1]; + + final boolean result = generateItems(pointer, tempIntArray, arrayItemDefs, arrayQuantity, arrayItemDefs.length); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean grantPromoItems(List inventories) { + int[] tempIntArray = new int[1]; + + final boolean result = grantPromoItems(pointer, tempIntArray); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean addPromoItem(List inventories, int itemDef) { + int[] tempIntArray = new int[1]; + + final boolean result = addPromoItem(pointer, tempIntArray, itemDef); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + // STEAM_ARRAY_COUNT(unArrayLength) int[] pArrayItemDefs + public boolean addPromoItems(List inventories, int[] arrayItemDefs) { + int[] tempIntArray = new int[1]; + + final boolean result = addPromoItems(pointer, tempIntArray, arrayItemDefs, arrayItemDefs.length); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean consumeItem(List inventories, SteamItemInstanceId itemConsume, int quantity) { + int[] tempIntArray = new int[1]; + + final boolean result = consumeItem(pointer, tempIntArray, itemConsume.handle, quantity); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + // STEAM_ARRAY_COUNT(unArrayGenerateLength) int[] pArrayGenerate, STEAM_ARRAY_COUNT(unArrayGenerateLength) int[] punArrayGenerateQuantity + // STEAM_ARRAY_COUNT(unArrayDestroyLength) SteamItemInstanceId[] pArrayDestroy, STEAM_ARRAY_COUNT(unArrayDestroyLength) int[] punArrayDestroyQuantity + public boolean exchangeItems(List inventories, int[] arrayGenerate, int[] arrayGenerateQuantity, int arrayGenerateLength, + SteamItemInstanceId[] arrayDestroy, int[] arrayDestroyQuantity, int arrayDestroyLength) { + int[] tempIntArray = new int[1]; + + final boolean result = exchangeItems(pointer, tempIntArray, arrayGenerate, arrayGenerateQuantity, arrayGenerateLength, + Arrays.stream(arrayDestroy).mapToLong(steamItemInstanceId -> steamItemInstanceId.handle).toArray(), arrayDestroyQuantity, arrayDestroyLength); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean transferItemQuantity(List inventories, SteamItemInstanceId itemIdSource, int quantity, SteamItemInstanceId itemIdDest) { + int[] tempIntArray = new int[1]; + + final boolean result = transferItemQuantity(pointer, tempIntArray, itemIdSource.handle, quantity, itemIdDest.handle); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + @Deprecated + public void sendItemDropHeartbeat() { + sendItemDropHeartbeat(pointer); + } + + public boolean triggerItemDrop(List inventories, int dropListDefinition) { + int[] tempIntArray = new int[1]; + + final boolean result = triggerItemDrop(pointer, tempIntArray, dropListDefinition); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean loadItemDefinitions() { + return loadItemDefinitions(pointer); + } + + public boolean getItemDefinitionIDs(List itemDefIDs) { + int size = getItemDefinitionIDSize(pointer); + final int[] tempIntArray = new int[size]; + + final boolean result = getItemDefinitionIDs(pointer, tempIntArray, size); + + if(result) { + itemDefIDs.addAll(Arrays.stream(tempIntArray).boxed().collect(Collectors.toList())); + } + + return result; + } + + public String getItemDefinitionPropertyKeys(int itemDefinition) { + return getItemDefinitionPropertyKeys(pointer, itemDefinition); + } + + public boolean getItemDefinitionProperty(int itemDefinition, String propertyName, List values) { + SteamInventoryValue steamValue = new SteamInventoryValue(); + + final boolean result = getItemDefinitionProperty(pointer, itemDefinition, propertyName, steamValue); + + values.add(steamValue.getValue()); + + return result; + } + + public SteamAPICall requestEligiblePromoItemDefinitionsIDs(SteamID steamID) { + return new SteamAPICall(requestEligiblePromoItemDefinitionsIDs(pointer, callback, steamID.handle)); + } + + public boolean getEligiblePromoItemDefinitionIDs(SteamID steamID, List itemDefIDs, int size) { + final int[] tempIntArray = new int[size]; + Arrays.fill(tempIntArray, -1); + + final boolean result = getEligiblePromoItemDefinitionIDs(pointer, steamID.handle, tempIntArray, size); + + if(result) { + itemDefIDs.addAll(Arrays.stream(tempIntArray).boxed().collect(Collectors.toList())); + } + + return result; + } + + public SteamAPICall startPurchase(int[] arrayItemDefs, int[] arrayQuantity) { + return new SteamAPICall(startPurchase(pointer, callback, arrayItemDefs, arrayQuantity, arrayItemDefs.length)); + } + + public SteamAPICall requestPrices() { + return new SteamAPICall(requestPrices(pointer, callback)); + } + + public int getNumItemsWithPrices() { + return getNumItemsWithPrices(pointer); + } + + public boolean getItemsWithPrices(int[] arrayItemDefs, long[] currentPrices, long[] basePrices) { + return getItemsWithPrices(pointer, arrayItemDefs, currentPrices, basePrices, arrayItemDefs.length); + } + + public boolean getItemPrice(int itemDefinition, long[] currentPrice, long[] basePrice) { + return getItemPrice(pointer, itemDefinition, currentPrice, basePrice); + } + + public SteamInventoryUpdateHandle startUpdateProperties() { + return new SteamInventoryUpdateHandle(startUpdateProperties(pointer)); + } + + public boolean removeProperty(SteamInventoryUpdateHandle updateHandle, SteamItemInstanceId itemID, String propertyName) { + return removeProperty(pointer, updateHandle.handle, itemID.handle, propertyName); + } + + public boolean setProperty(SteamInventoryUpdateHandle updateHandle, SteamItemInstanceId itemID, String propertyName, String value) { + return setProperty(pointer, updateHandle.handle, itemID.handle, propertyName, value); + } + + public boolean setProperty(SteamInventoryUpdateHandle updateHandle, SteamItemInstanceId itemID, String propertyName, boolean value) { + return setProperty(pointer, updateHandle.handle, itemID.handle, propertyName, value); + } + + public boolean setProperty(SteamInventoryUpdateHandle updateHandle, SteamItemInstanceId itemID, String propertyName, long value) { + return setProperty(pointer, updateHandle.handle, itemID.handle, propertyName, value); + } + + public boolean setProperty(SteamInventoryUpdateHandle updateHandle, SteamItemInstanceId itemID, String propertyName, float value) { + return setProperty(pointer, updateHandle.handle, itemID.handle, propertyName, value); + } + + public boolean submitUpdateProperties(SteamInventoryUpdateHandle updateHandle, List inventories) { + int[] tempIntArray = new int[1]; + + final boolean result = submitUpdateProperties(pointer, updateHandle.handle, tempIntArray); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + public boolean inspectItem(List inventories, String itemToken) { + int[] tempIntArray = new int[1]; + + final boolean result = inspectItem(pointer, tempIntArray, itemToken); + + if(result) { + inventories.addAll(SteamInventoryHandle.mapToHandles(tempIntArray)); + } + + return result; + } + + // @off + + /*JNI + #include "SteamInventoryCallback.h" + #include + */ + + private static native long createCallback(SteamInventoryCallbackAdapter javaCallback); /* + return (intp) new SteamInventoryCallback(env, javaCallback); + */ + + private static native int getResultStatus(long pointer, int resultHandle); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetResultStatus((SteamInventoryResult_t) resultHandle); + */ + + private static native int getResultItemsLength(long pointer, int resultHandle); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + + uint32 count = 0; + bool success = inventory->GetResultItems((SteamInventoryResult_t) resultHandle, NULL, &count); + + if(success) { + return count; + } + + return -1; + */ + + private static native boolean getResultItems(long pointer, int resultHandle, SteamItemDetails[] itemDetails); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + + uint32 count = 0; + bool success = false; + if(inventory->GetResultItems((SteamInventoryResult_t) resultHandle, NULL, &count)) { + std::vector results; + results.resize(count); + + success = inventory->GetResultItems((SteamInventoryResult_t) resultHandle, results.data(), &count); + + if (success) { + for(unsigned int a = 0; a < count; a = a + 1) { + jclass clazz = env->GetObjectClass(env->GetObjectArrayElement(itemDetails, a)); + + jfieldID field = env->GetFieldID(clazz, "itemId", "J"); + env->SetLongField(env->GetObjectArrayElement(itemDetails, a), field, (jlong) results[a].m_itemId); + + field = env->GetFieldID(clazz, "itemDefinition", "I"); + env->SetIntField(env->GetObjectArrayElement(itemDetails, a), field, (jint) results[a].m_iDefinition); + + field = env->GetFieldID(clazz, "quantity", "S"); + env->SetShortField(env->GetObjectArrayElement(itemDetails, a), field, (jshort) results[a].m_unQuantity); + + field = env->GetFieldID(clazz, "flags", "S"); + env->SetShortField(env->GetObjectArrayElement(itemDetails, a), field, (jshort) results[a].m_unFlags); + } + } + } + + return success; + */ + + private static native String getResultItemPropertyKeys(long pointer, int resultHandle, int itemIndex); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + char *valueBuffer = (char*) malloc(1); + uint32 valueBufferSizeOut = 0; + + inventory->GetResultItemProperty((SteamInventoryResult_t) resultHandle, itemIndex, NULL, valueBuffer, &valueBufferSizeOut); + valueBuffer = (char*) malloc(valueBufferSizeOut); + inventory->GetResultItemProperty((SteamInventoryResult_t) resultHandle, itemIndex, NULL, valueBuffer, &valueBufferSizeOut); + + return env->NewStringUTF(valueBuffer); + */ + + private static native boolean getResultItemProperty(long pointer, int resultHandle, int itemIndex, String propertyName, SteamInventoryValue value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + char *valueBuffer = (char*) malloc(1); + uint32 valueBufferSizeOut = 0; + + inventory->GetResultItemProperty((SteamInventoryResult_t) resultHandle, itemIndex, propertyName, valueBuffer, &valueBufferSizeOut); + valueBuffer = (char*) malloc(valueBufferSizeOut); + bool success = inventory->GetResultItemProperty((SteamInventoryResult_t) resultHandle, itemIndex, propertyName, valueBuffer, &valueBufferSizeOut); + + jclass valueClazz = env->GetObjectClass(value); + + jfieldID field = env->GetFieldID(valueClazz, "value", "Ljava/lang/String;"); + env->SetObjectField(value, field, env->NewStringUTF(valueBuffer)); + + return success; + */ + + private static native int getResultTimestamp(long pointer, int resultHandle); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetResultTimestamp((SteamInventoryResult_t) resultHandle); + */ + + private static native boolean checkResultSteamID(long pointer, int resultHandle, long steamIDExpected); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->CheckResultSteamID((SteamInventoryResult_t) resultHandle, (uint64) steamIDExpected); + */ + + private static native void destroyResult(long pointer, int resultHandle); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->DestroyResult((SteamInventoryResult_t) resultHandle); + */ + + private static native boolean getAllItems(long pointer, int[] resultHandles); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetAllItems((SteamInventoryResult_t*) resultHandles); + */ + + private static native boolean getItemsByID(long pointer, int[] resultHandles, long[] instanceIDs, int countInstanceIDs); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetItemsByID((SteamInventoryResult_t*) resultHandles, (SteamItemInstanceID_t*) instanceIDs, countInstanceIDs); + */ + + private static native int serializeResultSize(long pointer, int resultHandle); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + uint32 outBufferSize = 0; + + bool success = inventory->SerializeResult((SteamInventoryResult_t) resultHandle, NULL, &outBufferSize); + + if(success) { + return outBufferSize; + } else { + return -1; + } + */ + + private static native boolean serializeResult(long pointer, int resultHandle, ByteBuffer outBuffer, int offset, int outBufferSize); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SerializeResult((SteamInventoryResult_t) resultHandle, &outBuffer[offset], (uint32*) &outBufferSize); + */ + + private static native boolean deserializeResult(long pointer, int[] resultHandles, ByteBuffer buffer, int offset, int bufferSize, boolean reserved); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->DeserializeResult((SteamInventoryResult_t*) resultHandles, &buffer[offset], bufferSize, reserved); + */ + + private static native boolean generateItems(long pointer, int[] resultHandles, int[] arrayItemDefs, int[] arrayQuantity, int arrayLength); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GenerateItems((SteamInventoryResult_t*) resultHandles, (SteamItemDef_t*) arrayItemDefs, (uint32*) arrayQuantity, arrayLength); + */ + + private static native boolean grantPromoItems(long pointer, int[] resultHandles); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GrantPromoItems((SteamInventoryResult_t*) resultHandles); + */ + + private static native boolean addPromoItem(long pointer, int[] resultHandles, int itemDef); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->AddPromoItem((SteamInventoryResult_t*) resultHandles, itemDef); + */ + + private static native boolean addPromoItems(long pointer, int[] resultHandles, int[] arrayItemDefs, int arrayLength); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->AddPromoItems((SteamInventoryResult_t*) resultHandles, (SteamItemDef_t*) arrayItemDefs, arrayLength); + */ + + private static native boolean consumeItem(long pointer, int[] resultHandles, long itemConsume, int quantity); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->ConsumeItem((SteamInventoryResult_t*) resultHandles, (SteamItemInstanceID_t) itemConsume, quantity); + */ + + private static native boolean exchangeItems(long pointer, int[] resultHandles, int[] arrayGenerate, int[] arrayGenerateQuantity, int arrayGenerateLength, + long[] arrayDestroy, int[] arrayDestroyQuantity, int arrayDestroyLength); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->ExchangeItems((SteamInventoryResult_t*) resultHandles, (SteamItemDef_t*) arrayGenerate, (uint32*) arrayGenerateQuantity, arrayGenerateLength, (SteamItemInstanceID_t*) arrayDestroy, (uint32*) arrayDestroyQuantity, arrayDestroyLength); + */ + + private static native boolean transferItemQuantity(long pointer, int[] resultHandles, long itemIdSource, int quantity, long itemIdDest); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->TransferItemQuantity((SteamInventoryResult_t*) resultHandles, (SteamItemInstanceID_t) itemIdSource, quantity, (SteamItemInstanceID_t) itemIdDest); + */ + + private static native void sendItemDropHeartbeat(long pointer); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SendItemDropHeartbeat(); + */ + + private static native boolean triggerItemDrop(long pointer, int[] resultHandles, int dropListDefinition); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->TriggerItemDrop((SteamInventoryResult_t*) resultHandles, dropListDefinition); + */ + + private static native boolean loadItemDefinitions(long pointer); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->LoadItemDefinitions(); + */ + + private static native int getItemDefinitionIDSize(long pointer); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + uint32 count = 0; + + bool success = inventory->GetItemDefinitionIDs(NULL, &count); + + if(success) { + return count; + } + + return -1; + */ + + private static native boolean getItemDefinitionIDs(long pointer, int[] itemDefIDs, int itemDefIDsArraySize); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetItemDefinitionIDs((SteamItemDef_t*) itemDefIDs, (uint32*) &itemDefIDsArraySize); + */ + + private static native String getItemDefinitionPropertyKeys(long pointer, int itemDefinition); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + char *valueBuffer = (char*) malloc(1); + uint32 valueBufferSizeOut = 0; + + inventory->GetItemDefinitionProperty((SteamItemDef_t) itemDefinition, NULL, valueBuffer, &valueBufferSizeOut); + valueBuffer = (char*) malloc(valueBufferSizeOut); + inventory->GetItemDefinitionProperty((SteamItemDef_t) itemDefinition, NULL, valueBuffer, &valueBufferSizeOut); + + return env->NewStringUTF(valueBuffer); + */ + + private static native boolean getItemDefinitionProperty(long pointer, int itemDefinition, String propertyName, SteamInventoryValue value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + char *valueBuffer = (char*) malloc(1); + uint32 valueBufferSizeOut = 0; + + inventory->GetItemDefinitionProperty((SteamItemDef_t) itemDefinition, propertyName, valueBuffer, &valueBufferSizeOut); + valueBuffer = (char*) malloc(valueBufferSizeOut); + bool success = inventory->GetItemDefinitionProperty((SteamItemDef_t) itemDefinition, propertyName, valueBuffer, &valueBufferSizeOut); + + jclass valueClazz = env->GetObjectClass(value); + + jfieldID field = env->GetFieldID(valueClazz, "value", "Ljava/lang/String;"); + env->SetObjectField(value, field, env->NewStringUTF(valueBuffer)); + + return success; + */ + + private static native long requestEligiblePromoItemDefinitionsIDs(long pointer, long callback, long steamID); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + SteamInventoryCallback* cb = (SteamInventoryCallback*) callback; + SteamAPICall_t handle = inventory->RequestEligiblePromoItemDefinitionsIDs(CSteamID((uint64) steamID)); + cb->onSteamInventoryEligiblePromoItemDefIDsCall.Set(handle, cb, &SteamInventoryCallback::onSteamInventoryEligiblePromoItemDefIDs); + return handle; + */ + + private static native boolean getEligiblePromoItemDefinitionIDs(long pointer, long steamID, int[] itemDefIDs, int itemDefIDsArraySize); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetEligiblePromoItemDefinitionIDs((uint64) steamID, (SteamItemDef_t*) itemDefIDs, (uint32*) &itemDefIDsArraySize); + */ + + private static native long startPurchase(long pointer, long callback, int[] arrayItemDefs, int[] arrayQuantity, int arrayLength); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + SteamInventoryCallback* cb = (SteamInventoryCallback*) callback; + SteamAPICall_t handle = inventory->StartPurchase((SteamItemDef_t*) arrayItemDefs, (uint32*) arrayQuantity, arrayLength); + cb->onSteamInventoryStartPurchaseResultCall.Set(handle, cb, &SteamInventoryCallback::onSteamInventoryStartPurchaseResult); + return handle; + */ + + private static native long requestPrices(long pointer, long callback); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + SteamInventoryCallback* cb = (SteamInventoryCallback*) callback; + SteamAPICall_t handle = inventory->RequestPrices(); + cb->onSteamInventoryRequestPricesResultCall.Set(handle, cb, &SteamInventoryCallback::onSteamInventoryRequestPricesResult); + return handle; + */ + + private static native int getNumItemsWithPrices(long pointer); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetNumItemsWithPrices(); + */ + + private static native boolean getItemsWithPrices(long pointer, int[] arrayItemDefs, long[] currentPrices, long[] basePrices, int arrayLength); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetItemsWithPrices((SteamItemDef_t*) arrayItemDefs, (uint64*) currentPrices, (uint64*) basePrices, arrayLength); + */ + + private static native boolean getItemPrice(long pointer, int itemDefinition, long[] currentPrice, long[] basePrice); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->GetItemPrice((SteamItemDef_t) itemDefinition, (uint64*) currentPrice, (uint64*) basePrice); + */ + + private static native long startUpdateProperties(long pointer); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->StartUpdateProperties(); + */ + + private static native boolean removeProperty(long pointer, long updateHandle, long itemID, String propertyName); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->RemoveProperty((SteamInventoryUpdateHandle_t) updateHandle, (SteamItemInstanceID_t) itemID, propertyName); + */ + + private static native boolean setProperty(long pointer, long updateHandle, long itemID, String propertyName, String value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SetProperty((SteamInventoryUpdateHandle_t) updateHandle, (SteamItemInstanceID_t) itemID, propertyName, (char*) value); + */ + + private static native boolean setProperty(long pointer, long updateHandle, long itemID, String propertyName, boolean value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SetProperty((SteamInventoryUpdateHandle_t) updateHandle, (SteamItemInstanceID_t) itemID, propertyName, (bool) value); + */ + + private static native boolean setProperty(long pointer, long updateHandle, long itemID, String propertyName, long value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SetProperty((SteamInventoryUpdateHandle_t) updateHandle, (SteamItemInstanceID_t) itemID, propertyName, (int64) value); + */ + + private static native boolean setProperty(long pointer, long updateHandle, long itemID, String propertyName, float value); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SetProperty((SteamInventoryUpdateHandle_t) updateHandle, (SteamItemInstanceID_t) itemID, propertyName, (float) value); + */ + + private static native boolean submitUpdateProperties(long pointer, long updateHandle, int[] resultHandles); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->SubmitUpdateProperties((SteamInventoryUpdateHandle_t) updateHandle, (SteamInventoryResult_t*) resultHandles); + */ + + private static native boolean inspectItem(long pointer, int[] resultHandles, String itemToken); /* + ISteamInventory* inventory = (ISteamInventory*) pointer; + return inventory->InspectItem((SteamInventoryResult_t*) resultHandles, itemToken); + */ +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallback.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallback.java new file mode 100644 index 00000000..2da0a1fe --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallback.java @@ -0,0 +1,15 @@ +package com.codedisaster.steamworks; + +public interface SteamInventoryCallback { + void onSteamInventoryResultReady(SteamInventoryHandle inventory, SteamResult result); + + void onSteamInventoryFullUpdate(SteamInventoryHandle inventory); + + void onSteamInventoryDefinitionUpdate(); + + void onSteamInventoryEligiblePromoItemDefIDs(SteamResult result, SteamID steamID, int eligiblePromoItemDefs, boolean cachedData); + + void onSteamInventoryStartPurchaseResult(SteamResult result, long orderID, long transactionID); + + void onSteamInventoryRequestPricesResult(SteamResult result, String currency); +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallbackAdapter.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallbackAdapter.java new file mode 100644 index 00000000..9be36af4 --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryCallbackAdapter.java @@ -0,0 +1,32 @@ +package com.codedisaster.steamworks; + +@SuppressWarnings("unused") +public class SteamInventoryCallbackAdapter extends SteamCallbackAdapter { + SteamInventoryCallbackAdapter(SteamInventoryCallback callback) { + super(callback); + } + + void onSteamInventoryResultReady(int handle, int result) { + callback.onSteamInventoryResultReady(new SteamInventoryHandle(handle), SteamResult.byValue(result)); + } + + void onSteamInventoryFullUpdate(int handle) { + callback.onSteamInventoryFullUpdate(new SteamInventoryHandle(handle)); + } + + void onSteamInventoryDefinitionUpdate() { + callback.onSteamInventoryDefinitionUpdate(); + } + + void onSteamInventoryEligiblePromoItemDefIDs(int result, long steamID, int eligiblePromoItemDefs, boolean cachedData) { + callback.onSteamInventoryEligiblePromoItemDefIDs(SteamResult.byValue(result), new SteamID(steamID), eligiblePromoItemDefs, cachedData); + } + + void onSteamInventoryStartPurchaseResult(int result, long orderID, long transactionID) { + callback.onSteamInventoryStartPurchaseResult(SteamResult.byValue(result), orderID, transactionID); + } + + void onSteamInventoryRequestPricesResult(int result, String currency) { + callback.onSteamInventoryRequestPricesResult(SteamResult.byValue(result), currency); + } +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryHandle.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryHandle.java new file mode 100644 index 00000000..7bba8557 --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryHandle.java @@ -0,0 +1,18 @@ +package com.codedisaster.steamworks; + +import java.util.*; +import java.util.stream.Collectors; + +public class SteamInventoryHandle extends SteamNativeIntHandle { + public static final int INVALID_VALUE = -1; + + public static final SteamInventoryHandle INVALID = new SteamInventoryHandle(INVALID_VALUE); + + SteamInventoryHandle(int handle) { + super(handle); + } + + public static List mapToHandles(int[] handlesAsInt) { + return Arrays.stream(handlesAsInt).filter(value -> value != INVALID_VALUE).boxed().map(SteamInventoryHandle::new).collect(Collectors.toList()); + } +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryUpdateHandle.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryUpdateHandle.java new file mode 100644 index 00000000..ff61dbaf --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamInventoryUpdateHandle.java @@ -0,0 +1,14 @@ +package com.codedisaster.steamworks; + +public class SteamInventoryUpdateHandle extends SteamNativeHandle { + + public static final SteamInventoryUpdateHandle INVALID = new SteamInventoryUpdateHandle(0xffffffffffffffffL); + + SteamInventoryUpdateHandle(long handle) { + super(handle); + } + + public boolean isValid() { + return handle != INVALID.handle; + } +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamItemInstanceId.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamItemInstanceId.java new file mode 100644 index 00000000..f31a02ff --- /dev/null +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamItemInstanceId.java @@ -0,0 +1,14 @@ +package com.codedisaster.steamworks; + +public class SteamItemInstanceId extends SteamNativeHandle { + + public static final SteamItemInstanceId INVALID = new SteamItemInstanceId(~0); + + public SteamItemInstanceId(long handle) { + super(handle); + } + + public boolean isValid() { + return handle != INVALID.handle; + } +} diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamMatchmaking.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamMatchmaking.java index 5aa6606b..e5a7edd3 100644 --- a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamMatchmaking.java +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamMatchmaking.java @@ -487,7 +487,7 @@ private static native boolean getLobbyDataByIndex(long pointer, long steamIDLobb ISteamMatchmaking* matchmaking = (ISteamMatchmaking*) pointer; MatchMakingKeyValuePair_t result; bool success = matchmaking->GetLobbyDataByIndex((uint64) steamIDLobby, lobbyDataIndex, - result.m_szKey, 256, result.m_szValue, 256); + result.m_szKey, 256, result.m_szValue, 8192); if (success) { jclass clazz = env->GetObjectClass(keyValuePair); diff --git a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamResult.java b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamResult.java index a42d8f01..ad58b188 100644 --- a/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamResult.java +++ b/java-wrapper/src/main/java/com/codedisaster/steamworks/SteamResult.java @@ -118,6 +118,9 @@ public enum SteamResult { AccountNotFriends(111), LimitedUserAccount(112), CantRemoveItem(113), + AccountDeleted(114), + ExistingUserCancelledLicense(115), + CommunityCooldown(116), /** * If this is returned(), we missed to "port" an Steam error code above. diff --git a/java-wrapper/src/main/native/SteamInventoryCallback.cpp b/java-wrapper/src/main/native/SteamInventoryCallback.cpp new file mode 100644 index 00000000..28549de3 --- /dev/null +++ b/java-wrapper/src/main/native/SteamInventoryCallback.cpp @@ -0,0 +1,53 @@ +#include "SteamInventoryCallback.h" + +SteamInventoryCallback::SteamInventoryCallback(JNIEnv* env, jobject callback) + : SteamCallbackAdapter(env, callback) + , m_CallbackSteamInventoryResultReady(this, &SteamInventoryCallback::onSteamInventoryResultReady) + , m_CallbackSteamInventoryFullUpdate(this, &SteamInventoryCallback::onSteamInventoryFullUpdate) + , m_CallbackSteamInventoryDefinitionUpdate(this, &SteamInventoryCallback::onSteamInventoryDefinitionUpdate) { +} + +SteamInventoryCallback::~SteamInventoryCallback() { + +} + +void SteamInventoryCallback::onSteamInventoryResultReady(SteamInventoryResultReady_t* callback) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryResultReady", "(II)V", + (jint) callback->m_handle, (jint) callback->m_result); + }); +} + +void SteamInventoryCallback::onSteamInventoryFullUpdate(SteamInventoryFullUpdate_t* callback) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryFullUpdate", "(I)V", + (jint) callback->m_handle); + }); +} + +void SteamInventoryCallback::onSteamInventoryDefinitionUpdate(SteamInventoryDefinitionUpdate_t* callback) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryDefinitionUpdate", "()V"); + }); +} + +void SteamInventoryCallback::onSteamInventoryEligiblePromoItemDefIDs(SteamInventoryEligiblePromoItemDefIDs_t* callback, bool error) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryEligiblePromoItemDefIDs", "(IJIZ)V", + (jint) callback->m_result, (jlong) callback->m_steamID.ConvertToUint64(), (jint) callback->m_numEligiblePromoItemDefs, (jboolean) callback->m_bCachedData); + }); +} + +void SteamInventoryCallback::onSteamInventoryStartPurchaseResult(SteamInventoryStartPurchaseResult_t* callback, bool error) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryStartPurchaseResult", "(IJJ)V", + (jint) callback->m_result, (jlong) callback->m_ulOrderID, (jlong) callback->m_ulTransID); + }); +} + +void SteamInventoryCallback::onSteamInventoryRequestPricesResult(SteamInventoryRequestPricesResult_t* callback, bool error) { + invokeCallback({ + callVoidMethod(env, "onSteamInventoryRequestPricesResult", "(ILjava/lang/String;)V", + (jint) callback->m_result, env->NewStringUTF(callback->m_rgchCurrency)); + }); +} diff --git a/java-wrapper/src/main/native/SteamInventoryCallback.h b/java-wrapper/src/main/native/SteamInventoryCallback.h new file mode 100644 index 00000000..3b389af6 --- /dev/null +++ b/java-wrapper/src/main/native/SteamInventoryCallback.h @@ -0,0 +1,24 @@ +#pragma once + +#include "SteamCallbackAdapter.h" +#include + +class SteamInventoryCallback : public SteamCallbackAdapter { + +public: + SteamInventoryCallback(JNIEnv* env, jobject callback); + ~SteamInventoryCallback(); + + STEAM_CALLBACK(SteamInventoryCallback, onSteamInventoryResultReady, SteamInventoryResultReady_t, m_CallbackSteamInventoryResultReady); + STEAM_CALLBACK(SteamInventoryCallback, onSteamInventoryFullUpdate, SteamInventoryFullUpdate_t, m_CallbackSteamInventoryFullUpdate); + STEAM_CALLBACK(SteamInventoryCallback, onSteamInventoryDefinitionUpdate, SteamInventoryDefinitionUpdate_t, m_CallbackSteamInventoryDefinitionUpdate); + + void onSteamInventoryEligiblePromoItemDefIDs(SteamInventoryEligiblePromoItemDefIDs_t* callback, bool error); + CCallResult onSteamInventoryEligiblePromoItemDefIDsCall; + + void onSteamInventoryStartPurchaseResult(SteamInventoryStartPurchaseResult_t* callback, bool error); + CCallResult onSteamInventoryStartPurchaseResultCall; + + void onSteamInventoryRequestPricesResult(SteamInventoryRequestPricesResult_t* callback, bool error); + CCallResult onSteamInventoryRequestPricesResultCall; +}; \ No newline at end of file diff --git a/java-wrapper/src/main/resources/steamworks4j.dll b/java-wrapper/src/main/resources/steamworks4j.dll index 9f048821..7f85f2d0 100644 Binary files a/java-wrapper/src/main/resources/steamworks4j.dll and b/java-wrapper/src/main/resources/steamworks4j.dll differ diff --git a/java-wrapper/src/main/resources/steamworks4j64.dll b/java-wrapper/src/main/resources/steamworks4j64.dll index 8093c79f..0105fdd4 100644 Binary files a/java-wrapper/src/main/resources/steamworks4j64.dll and b/java-wrapper/src/main/resources/steamworks4j64.dll differ diff --git a/jnigen/pom.xml b/jnigen/pom.xml index d0bda802..40be18e5 100644 --- a/jnigen/pom.xml +++ b/jnigen/pom.xml @@ -45,8 +45,8 @@ maven-compiler-plugin 3.0 - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/pom.xml b/pom.xml index fe966830..7dd1e847 100644 --- a/pom.xml +++ b/pom.xml @@ -18,5 +18,4 @@ server tests - diff --git a/server/pom.xml b/server/pom.xml index 6c3af1a6..47ace3e2 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -147,8 +147,8 @@ maven-compiler-plugin 3.0 - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/server/src/main/java/com/codedisaster/steamworks/SteamGameServer.java b/server/src/main/java/com/codedisaster/steamworks/SteamGameServer.java index 6dd984ae..e195a79c 100644 --- a/server/src/main/java/com/codedisaster/steamworks/SteamGameServer.java +++ b/server/src/main/java/com/codedisaster/steamworks/SteamGameServer.java @@ -199,10 +199,6 @@ public boolean requestUserGroupStatus(SteamID steamIDUser, SteamID steamIDGroup) return SteamGameServerNative.requestUserGroupStatus(pointer, steamIDUser.handle, steamIDGroup.handle); } - public int getPublicIP() { - return SteamGameServerNative.getPublicIP(pointer); - } - public boolean handleIncomingPacket(ByteBuffer data, int srcIP, short srcPort) { return SteamGameServerNative.handleIncomingPacket( pointer, data, data.position(), data.remaining(), srcIP, srcPort); diff --git a/server/src/main/java/com/codedisaster/steamworks/SteamGameServerNative.java b/server/src/main/java/com/codedisaster/steamworks/SteamGameServerNative.java index a7b8b1bc..fb3a2507 100644 --- a/server/src/main/java/com/codedisaster/steamworks/SteamGameServerNative.java +++ b/server/src/main/java/com/codedisaster/steamworks/SteamGameServerNative.java @@ -188,11 +188,6 @@ static native int beginAuthSession(long pointer, ByteBuffer authTicket, return server->RequestUserGroupStatus((uint64) steamIDUser, (uint64) steamIDGroup); */ - static native int getPublicIP(long pointer); /* - ISteamGameServer* server = (ISteamGameServer*) pointer; - return server->GetPublicIP(); - */ - static native boolean handleIncomingPacket(long pointer, ByteBuffer data, int offset, int size, int srcIP, short srcPort); /* ISteamGameServer* server = (ISteamGameServer*) pointer; diff --git a/server/src/main/resources/steamworks4j-encryptedappticket.dll b/server/src/main/resources/steamworks4j-encryptedappticket.dll index 52322352..6e99d910 100644 Binary files a/server/src/main/resources/steamworks4j-encryptedappticket.dll and b/server/src/main/resources/steamworks4j-encryptedappticket.dll differ diff --git a/server/src/main/resources/steamworks4j-encryptedappticket64.dll b/server/src/main/resources/steamworks4j-encryptedappticket64.dll index 3c30417d..7823d816 100644 Binary files a/server/src/main/resources/steamworks4j-encryptedappticket64.dll and b/server/src/main/resources/steamworks4j-encryptedappticket64.dll differ diff --git a/server/src/main/resources/steamworks4j-server.dll b/server/src/main/resources/steamworks4j-server.dll index 0df0889b..dfccc6ca 100644 Binary files a/server/src/main/resources/steamworks4j-server.dll and b/server/src/main/resources/steamworks4j-server.dll differ diff --git a/server/src/main/resources/steamworks4j-server64.dll b/server/src/main/resources/steamworks4j-server64.dll index c3c127ee..fc16581a 100644 Binary files a/server/src/main/resources/steamworks4j-server64.dll and b/server/src/main/resources/steamworks4j-server64.dll differ diff --git a/tests/pom.xml b/tests/pom.xml index 1807ad47..4e2039cc 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -40,8 +40,8 @@ maven-compiler-plugin 3.0 - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/tests/src/main/java/com/codedisaster/steamworks/test/SteamClientAPITest.java b/tests/src/main/java/com/codedisaster/steamworks/test/SteamClientAPITest.java index 498e53cc..87f649ef 100644 --- a/tests/src/main/java/com/codedisaster/steamworks/test/SteamClientAPITest.java +++ b/tests/src/main/java/com/codedisaster/steamworks/test/SteamClientAPITest.java @@ -4,7 +4,7 @@ import java.io.*; import java.nio.ByteBuffer; -import java.util.Collection; +import java.util.*; public class SteamClientAPITest extends SteamTestApp { @@ -281,12 +281,20 @@ public void onRequestUGCDetails(SteamUGCDetails details, SteamResult result) { @Override public void onCreateItem(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result) { + System.out.println("Create item result: result=" + result + ", needsToAcceptWLA: " + needsToAcceptWLA); + System.out.println("publishedFileID: " + publishedFileID); + SteamUGCUpdateHandle updateHandle = ugc.startItemUpdate(utils.getAppID(), publishedFileID); + ugc.setItemTitle(updateHandle, "Test UGC!"); + ugc.setItemDescription(updateHandle, "Dummy UGC file published by test application."); + ugc.setItemVisibility(updateHandle, SteamRemoteStorage.PublishedFileVisibility.Private); + ugc.submitItemUpdate(updateHandle, "Dummy UGC file published by test application."); } @Override public void onSubmitItemUpdate(SteamPublishedFileID publishedFileID, boolean needsToAcceptWLA, SteamResult result) { - + System.out.println("Submit itemupdate result: result=" + result + ", needsToAcceptWLA: " + needsToAcceptWLA); + System.out.println("publishedFileID: " + publishedFileID); } @Override @@ -356,15 +364,11 @@ public void onPersonaStateChange(SteamID steamID, SteamFriends.PersonaChange cha switch (change) { case Name: - System.out.println("Persona name received: " + - "accountID=" + steamID.getAccountID() + - ", name='" + friends.getFriendPersonaName(steamID) + "'"); + System.out.println("Persona name received: " + "accountID=" + steamID.getAccountID() + ", name='" + friends.getFriendPersonaName(steamID) + "'"); break; default: - System.out.println("Persona state changed (unhandled): " + - "accountID=" + steamID.getAccountID() + - ", change=" + change.name()); + System.out.println("Persona state changed (unhandled): " + "accountID=" + steamID.getAccountID() + ", change=" + change.name()); break; } } @@ -409,7 +413,6 @@ public void onSteamShutdown() { @Override protected void registerInterfaces() { - System.out.println("Register user ..."); user = new SteamUser(userCallback); @@ -432,7 +435,7 @@ protected void registerInterfaces() { friends = new SteamFriends(friendsCallback); System.out.println("Local user account ID: " + user.getSteamID().getAccountID()); - System.out.println("Local user steam ID: " + SteamID.getNativeHandle(user.getSteamID())); + System.out.println("Local user steam ID: " + SteamNativeHandle.getNativeHandle(user.getSteamID())); System.out.println("Local user friends name: " + friends.getPersonaName()); System.out.println("App ID: " + utils.getAppID()); @@ -461,7 +464,6 @@ protected void processUpdate() throws SteamException { @Override protected void processInput(String input) throws SteamException { - if (input.startsWith("stats global ")) { String[] cmd = input.substring("stats global ".length()).split(" "); if (cmd.length > 0) { @@ -548,6 +550,8 @@ protected void processInput(String input) throws SteamException { } catch (IOException e) { e.printStackTrace(); } + } else if (input.startsWith("file create")) { + ugc.createItem(utils.getAppID(), SteamRemoteStorage.WorkshopFileType.Community); } else if (input.startsWith("file delete ")) { String path = input.substring("file delete ".length()); if (remoteStorage.fileDelete(path)) { @@ -660,7 +664,6 @@ protected void processInput(String input) throws SteamException { boolean subscribed = apps.isSubscribedApp(Integer.parseInt(appId)); System.out.println("user described to app #" + appId + ": " + (subscribed ? "yes" : "no")); } - } public static void main(String[] arguments) { diff --git a/tests/src/main/java/com/codedisaster/steamworks/test/SteamInventoryTest.java b/tests/src/main/java/com/codedisaster/steamworks/test/SteamInventoryTest.java new file mode 100644 index 00000000..ecbf3c43 --- /dev/null +++ b/tests/src/main/java/com/codedisaster/steamworks/test/SteamInventoryTest.java @@ -0,0 +1,337 @@ +package com.codedisaster.steamworks.test; + +import com.codedisaster.steamworks.*; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class SteamInventoryTest extends SteamTestApp { + private SteamUser user; + private SteamFriends friends; + private SteamInventory inventory; + + private SteamUserCallback userCallback = new SteamUserCallback() { + @Override + public void onAuthSessionTicket(SteamAuthTicket authTicket, SteamResult result) { + + } + + @Override + public void onValidateAuthTicket(SteamID steamID, SteamAuth.AuthSessionResponse authSessionResponse, SteamID ownerSteamID) { + + } + + @Override + public void onMicroTxnAuthorization(int appID, long orderID, boolean authorized) { + + } + + @Override + public void onEncryptedAppTicket(SteamResult result) { + + } + }; + + private SteamFriendsCallback friendsCallback = new SteamFriendsCallback() { + @Override + public void onSetPersonaNameResponse(boolean success, boolean localSuccess, SteamResult result) { + + } + + @Override + public void onPersonaStateChange(SteamID steamID, SteamFriends.PersonaChange change) { + + switch (change) { + + case Name: + // System.out.println("Persona name received: " + "accountID=" + steamID.getAccountID() + ", name='" + friends.getFriendPersonaName(steamID) + "'"); + break; + + default: + // System.out.println("Persona state changed (unhandled): " + "accountID=" + steamID.getAccountID() + ", change=" + change.name()); + break; + } + } + + @Override + public void onGameOverlayActivated(boolean active) { + + } + + @Override + public void onGameLobbyJoinRequested(SteamID steamIDLobby, SteamID steamIDFriend) { + + } + + @Override + public void onAvatarImageLoaded(SteamID steamID, int image, int width, int height) { + + } + + @Override + public void onFriendRichPresenceUpdate(SteamID steamIDFriend, int appID) { + + } + + @Override + public void onGameRichPresenceJoinRequested(SteamID steamIDFriend, String connect) { + + } + + @Override + public void onGameServerChangeRequested(String server, String password) { + + } + }; + + private SteamInventoryCallback inventoryCallback = new SteamInventoryCallback() { + @Override + public void onSteamInventoryResultReady(SteamInventoryHandle inventoryHandle, SteamResult result) { + System.out.println("Inventory Result ready: " + result + ", " + SteamNativeIntHandle + .getNativeHandle(inventoryHandle)); + System.out.println(inventory.getResultStatus(inventoryHandle) + ": result of getResultStatus"); + } + + @Override + public void onSteamInventoryFullUpdate(SteamInventoryHandle inventoryHandle) { + System.out.println("Inventory full update"); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getResultStatus(inventoryHandle) + ": result of getResultStatus"); + System.out.println(inventory.getResultItemsLength(inventoryHandle) + ": result of getResultItemsLength"); + System.out.println(inventory.getResultItems(inventoryHandle, itemDetails) + ": result of getResultItems, Details: " + itemDetails.get(0)); + System.out.println(inventory.getResultItemPropertyKeys(inventoryHandle, 0) + ": result of getResultItemPropertyKeys for itemIndex 0"); + final List properties = new ArrayList<>( + Arrays.asList(inventory.getResultItemPropertyKeys(inventoryHandle, 0).split(","))); + final List values = new ArrayList<>(); + System.out.println(inventory.getResultItemProperty(inventoryHandle, 0, properties.get(0), values) + ": result of getResultItemProperty for " + properties.get(0) + ": " + values.get(0)); + Optional propertyTestItem = itemDetails.stream().filter(itemDetail -> itemDetail.getItemDefinition() == 1300).findFirst(); + if(propertyTestItem.isPresent()) { + values.clear(); + System.out.println(inventory.getResultItemProperty(inventoryHandle, itemDetails.indexOf(propertyTestItem.get()), "dynamic_props", values) + ": result of getResultItemProperty for dynamic_props: " + values.get(0)); + } + System.out.println(inventory.getResultTimestamp(inventoryHandle) + ": result of getResultTimestamp"); + System.out.println(inventory.checkResultSteamID(inventoryHandle, user.getSteamID()) + ": result of checkResultSteamID"); + int friendsSize = friends.getFriendCount(SteamFriends.FriendFlags.Immediate); + System.out.println(inventory.checkResultSteamID(inventoryHandle, friends.getFriendByIndex(friendsSize-1, SteamFriends.FriendFlags.Immediate)) + ": result of checkResultSteamID"); + int bufferSize = inventory.getSizeNeededForResultSerialization(inventoryHandle); + System.out.println(bufferSize + ": result of getSizeNeededForResultSerialization"); + final ByteBuffer serializedResult = ByteBuffer.allocateDirect(bufferSize); + final List inventories = new ArrayList<>(); + try { + System.out.println(inventory.serializeResult(inventoryHandle, serializedResult) + ": result of serializeResult, serializedHandle: " + serializedResult + ", Handle: " + inventoryHandle); + System.out.println(inventory.deserializeResult(inventories, serializedResult) + ": result of deserializeResult, deserializedHandle: " + inventories.get(0)); + } catch(SteamException e) { + e.printStackTrace(); + } + inventory.destroyResult(inventories.get(0)); + inventories.clear(); + } + + @Override + public void onSteamInventoryDefinitionUpdate() { + System.out.println("Inventory definition update"); + final List itemDefs = new ArrayList<>(); + System.out.println(inventory.getItemDefinitionIDs(itemDefs) + ": result of getItemDefinitionIDs, itemDefs " + itemDefs); + } + + @Override + public void onSteamInventoryEligiblePromoItemDefIDs(SteamResult result, SteamID steamID, + int eligiblePromoItemDefs, boolean cachedData) { + System.out.println(result + " Inventory Eligible Promo Items for user: " + steamID.getAccountID() + ", Count: " + eligiblePromoItemDefs + ", cached: " + cachedData); + final List eligiblePromoItemDefIDs = new ArrayList<>(); + System.out.println(inventory.getEligiblePromoItemDefinitionIDs(user.getSteamID(), eligiblePromoItemDefIDs, eligiblePromoItemDefs) + ": result of getEligiblePromoItemDefinitionIDs, itemIds: " + eligiblePromoItemDefs); + } + + @Override + public void onSteamInventoryStartPurchaseResult(SteamResult result, long orderID, long transactionID) { + System.out.println(result + " Inventory Start Purchase, OrderID: " + orderID + ", transactionID: " + transactionID); + } + + @Override + public void onSteamInventoryRequestPricesResult(SteamResult result, String currency) { + System.out.println(result + " Inventory Request Prices: " + currency); + } + }; + + @Override + protected void registerInterfaces() throws SteamException { + System.out.println("Register user ..."); + user = new SteamUser(userCallback); + + System.out.println("Register Friends ..."); + friends = new SteamFriends(friendsCallback); + + System.out.println("Register Inventory ..."); + inventory = new SteamInventory(inventoryCallback); + } + + @Override + protected void unregisterInterfaces() throws SteamException { + user.dispose(); + friends.dispose(); + inventory.dispose(); + } + + @Override + protected void processUpdate() throws SteamException { + + } + + @Override + protected void processInput(String input) throws SteamException { + if (input.startsWith("inventory getAllItems")) { + final List inventories = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories) + ": result of getAllItems, Handle: " + SteamNativeIntHandle.getNativeHandle(inventories.get(0))); + } else if (input.startsWith("inventory loadItemDefinitions")) { + System.out.println(inventory.loadItemDefinitions() + ": result of loadItemDefinitions"); + } else if (input.startsWith("inventory requestEligiblePromoItemDefinitionsIDs")) { + System.out.println(inventory.requestEligiblePromoItemDefinitionsIDs(user.getSteamID()).isValid() + ": result of requestEligiblePromoItemDefinitionsIDs"); + } else if (input.startsWith("inventory addPromoItem ")) { + String[] params = input.substring("inventory addPromoItem ".length()).split(" "); + final List inventories = new ArrayList<>(); + System.out.println(inventory.addPromoItem(inventories, Integer.parseInt(params[0])) + ": result of addPromoItem, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory addPromoItems ")) { + String[] params = input.substring("inventory addPromoItems ".length()).split(" "); + int[] ids = Arrays.stream(params).mapToInt(Integer::parseInt).toArray(); + final List inventories = new ArrayList<>(); + System.out.println(inventory.addPromoItems(inventories, ids) + ": result of addPromoItems, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory generateItems")) { + final List inventories = new ArrayList<>(); + System.out.println(inventory.generateItems(inventories, new int[]{1000}, new int[]{1}) + ": result of generateItems, Handle: " + inventories.get(0)); + System.out.println(inventory.generateItems(inventories, new int[]{1100}, new int[]{2}) + ": result of generateItems, Handle: " + inventories.get(0)); + System.out.println(inventory.generateItems(inventories, new int[]{1300}, new int[]{1}) + ": result of generateItems, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory grantPromoItems")) { + final List inventories = new ArrayList<>(); + System.out.println(inventory.grantPromoItems(inventories) + ": result of grantPromoItems, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory consumeItem")) { + final List inventories = new ArrayList<>(); + System.out.println(inventory.consumeItem(inventories, new SteamItemInstanceId(100L), 0) + ": result of consumeItem for ID 100, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory exchangeItems")) { + final List inventories = new ArrayList<>(); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories)); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + e.printStackTrace(); + } + System.out.println(inventory.getResultItems(inventories.get(0), itemDetails)); + final List itemInstances = new ArrayList<>(); + final List items1 = itemDetails.stream().filter(details -> details.getItemDefinition() == 1000 && details.getQuantity() == 1).map(SteamInventory.SteamItemDetails::getItemId).collect( + Collectors.toList()); + final List items2 = itemDetails.stream().filter(details -> details.getItemDefinition() == 1100 && details.getQuantity() == 2).map(SteamInventory.SteamItemDetails::getItemId).collect(Collectors.toList()); + itemInstances.add(items1.get(0)); + itemInstances.add(items2.get(0)); + System.out.println(inventory.exchangeItems(inventories, new int[]{1200}, new int[]{1}, 1, + itemInstances.toArray(new SteamItemInstanceId[0]), new int[]{1, 2}, itemInstances.size()) + ": result of exchangeItems"); + } else if (input.startsWith("inventory transferItemQuantity stack")) { + final List inventories = new ArrayList<>(); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories)); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + e.printStackTrace(); + } + System.out.println(inventory.getResultItems(inventories.get(0), itemDetails)); + final List items = itemDetails.stream().filter(details -> details.getItemDefinition() == 1100).map(SteamInventory.SteamItemDetails::getItemId).collect(Collectors.toList()); + System.out.println(inventory.transferItemQuantity(inventories, items.get(1), 1, items.get(0)) + ": result of transferItemQuantity"); + } else if (input.startsWith("inventory transferItemQuantity unstack")) { + final List inventories = new ArrayList<>(); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories)); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + e.printStackTrace(); + } + System.out.println(inventory.getResultItems(inventories.get(0), itemDetails)); + final List items = itemDetails.stream().filter(details -> details.getItemDefinition() == 1100).map(SteamInventory.SteamItemDetails::getItemId).collect(Collectors.toList()); + System.out.println(inventory.transferItemQuantity(inventories, items.get(0), 1, SteamItemInstanceId.INVALID) + ": result of transferItemQuantity"); + } else if (input.startsWith("inventory sendItemDropHeartbeat")) { + inventory.sendItemDropHeartbeat(); + } else if (input.startsWith("inventory triggerItemDrop")) { + final List inventories = new ArrayList<>(); + System.out.println(inventory.triggerItemDrop(inventories, 100) + ": result of triggerItemDrop, Handle: " + inventories.get(0)); + } else if (input.startsWith("inventory getItemDefinitionProperty")) { + final List values = new ArrayList<>(); + final List properties = new ArrayList<>(Arrays.asList(inventory.getItemDefinitionPropertyKeys(100).split(","))); + System.out.println(inventory.getItemDefinitionProperty(100, properties.get(0), values) + ": result of getItemDefinitionProperty, values: " + values); + } else if (input.startsWith("inventory startPurchase")) { + System.out.println(inventory.startPurchase(new int[]{1100}, new int[]{5}).isValid() + ": result of startPurchase"); + } else if (input.startsWith("inventory requestPrices")) { + System.out.println(inventory.requestPrices().isValid() + ": result of requestPrices"); + } else if (input.startsWith("inventory getNumItemsWithPrices")) { + System.out.println(inventory.getNumItemsWithPrices() + ": result of getNumItemsWithPrices"); + } else if (input.startsWith("inventory getItemsWithPrices")) { + int size = inventory.getNumItemsWithPrices(); + int[] itemDefs = new int[size]; + long[] itemCurrentPrices = new long[size]; + long[] itemBasePrices = new long[size]; + Arrays.fill(itemDefs, -1); + Arrays.fill(itemCurrentPrices, -1); + Arrays.fill(itemBasePrices, -1); + System.out.println(inventory.getItemsWithPrices(itemDefs, itemCurrentPrices, itemBasePrices) + ": result of getNumItemsWithPrices"); + System.out.println(Arrays.toString(itemDefs) + ": itemDefs"); + System.out.println(Arrays.toString(itemCurrentPrices) + ": itemCurrentPrices"); + System.out.println(Arrays.toString(itemBasePrices) + ": itemBasePrices"); + } else if (input.startsWith("inventory getItemPrice")) { + long[] itemCurrentPrices = new long[1]; + long[] itemBasePrices = new long[1]; + Arrays.fill(itemCurrentPrices, -1); + Arrays.fill(itemBasePrices, -1); + System.out.println(inventory.getItemPrice(1100, itemCurrentPrices, itemBasePrices) + ": result of getItemPrice"); + System.out.println(itemCurrentPrices[0] + ": itemCurrentPrices"); + System.out.println(itemBasePrices[0] + ": itemBasePrices"); + } else if (input.startsWith("inventory UpdateProperties ")) { + String[] params = input.substring("inventory UpdateProperties ".length()).split(" "); + final List inventories = new ArrayList<>(); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories)); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + e.printStackTrace(); + } + System.out.println(inventory.getResultItems(inventories.get(0), itemDetails)); + final List items = itemDetails.stream().filter(details -> details.getItemDefinition() == 1300).map(SteamInventory.SteamItemDetails::getItemId).collect(Collectors.toList()); + final SteamInventoryUpdateHandle updateHandle = inventory.startUpdateProperties(); + System.out.println(updateHandle.isValid() + ": result of startUpdateProperties"); + System.out.println(inventory.setProperty(updateHandle, items.get(0), params[0], 10L) + ": result of setProperty for property: " + params[0]); + System.out.println(inventory.submitUpdateProperties(updateHandle, inventories) + ": result of submitUpdateProperties"); + } else if (input.startsWith("inventory removeProperty ")) { + String[] params = input.substring("inventory removeProperty ".length()).split(" "); + final List inventories = new ArrayList<>(); + final List itemDetails = new ArrayList<>(); + System.out.println(inventory.getAllItems(inventories)); + try { + Thread.sleep(1000); + } catch(InterruptedException e) { + e.printStackTrace(); + } + System.out.println(inventory.getResultItems(inventories.get(0), itemDetails)); + final List items = itemDetails.stream().filter(details -> details.getItemDefinition() == 1300).map(SteamInventory.SteamItemDetails::getItemId).collect(Collectors.toList()); + final SteamInventoryUpdateHandle updateHandle = inventory.startUpdateProperties(); + System.out.println(updateHandle + ": result of startUpdateProperties"); + System.out.println(inventory.removeProperty(updateHandle, items.get(0), params[0]) + ": result of removeProperty for property: " + params[0]); + System.out.println(inventory.submitUpdateProperties(updateHandle, inventories) + ": result of submitUpdateProperties"); + } else if (input.startsWith("inventory inspectItem ")) { + final List inventories = new ArrayList<>(); + String[] params = input.substring("inventory inspectItem ".length()).split(" "); + System.out.println(inventory.inspectItem(inventories, params[0])); + } else if (input.startsWith("inventory getItemsByID")) { + final List itemIds = new ArrayList<>(); + final List inventories = new ArrayList<>(); + itemIds.add(new SteamItemInstanceId(100L)); + System.out.println(inventory.getItemsByID(inventories, itemIds) + ": result of getItemsByID for ID 100"); + } + } + + public static void main(String[] arguments) { + new SteamInventoryTest().clientMain(arguments); + } +} diff --git a/tests/src/main/resources/inventoryTestItemDefs.json b/tests/src/main/resources/inventoryTestItemDefs.json new file mode 100644 index 00000000..25da3964 --- /dev/null +++ b/tests/src/main/resources/inventoryTestItemDefs.json @@ -0,0 +1,99 @@ +{ + "appid": 688610, + "items": [ + { + "itemdefid": 10, + "type": "playtimegenerator", + "bundle": "1000x100;1100x50;1300x25;1400x15;1500x10;", + "name": "Drop Generator", + "name_color": "7D6D00", + "background_color": "3C352E", + "item_slot": "generator", + "item_quality": 0, + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "tradable": false, + "marketable": false + }, + { + "itemdefid": 1000, + "type": "item", + "price_category": "1;VLV100", + "name_english": "Exchange Item 1", + "description_english": "First Item for the Exchange-Test", + "store_tags": "hat", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "tradable": true, + "marketable": true + }, + { + "itemdefid": 1100, + "type": "item", + "price_category": "1;VLV100", + "name_english": "Exchange Item 2", + "description_english": "Second Item for the Exchange-Test", + "store_tags": "hat", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "tradable": true, + "marketable": true + }, + { + "itemdefid": 1200, + "type": "item", + "price_category": "1;VLV100", + "name_english": "Exchange ResultItem", + "description_english": "The Item which will be granted in exchange for 1x Item 1 and 2x Item 2", + "store_tags": "hat", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "exchange": "1000x1,1100x2", + "tradable": true, + "marketable": true + }, + { + "itemdefid": 1300, + "type": "item", + "price_category": "1;VLV1500", + "name_english": "Property TestItem", + "description_english": "The Item which will be used for testing the dynamic properties", + "store_tags": "hat;weapon", + "tags": "weapon:hat", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "tradable": true, + "marketable": true + }, + { + "itemdefid": 1400, + "type": "item", + "price_category": "1;VLV2500", + "name_english": "Promo TestItem", + "description_english": "The Item which will be used for testing the Promo methods", + "store_tags": "hat", + "tags": "promo", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "promo": "manual", + "granted_manually": true, + "tradable": true, + "marketable": true + }, + { + "itemdefid": 1500, + "type": "item", + "price_category": "1;VLV2500", + "name_english": "Promo TestItem", + "description_english": "The Item which will be used for testing the Promo methods", + "store_tags": "hat", + "tags": "promo", + "icon_url": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "icon_url_large": "https://wiki.teamfortress.com/w/images/1/1b/Backpack_Anger.png", + "promo": "manual", + "granted_manually": true, + "tradable": true, + "marketable": true + } + ] +} \ No newline at end of file