Skip to content

Commit 90cf2fd

Browse files
committed
Add datapack config
1 parent f5c0769 commit 90cf2fd

11 files changed

+219
-21
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@ build
3232
run
3333
/Mod/.gradle
3434
/Mod/build/
35-
Mod/run/
35+
Mod/run/
36+
37+
tokens.properties

README.md

+22-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,28 @@
11
# Stacc
2-
infinite stacking for fabric
2+
Infinite* item stacking for fabric. \
3+
https://www.curseforge.com/minecraft/mc-mods/stacc-api \
4+
https://modrinth.com/mod/stacc-api
35

4-
# API
56
~~As of November 9th 2020, Stacc is now an 'api' mod. However there is no api, just include the mod inside your mod and now you can set `Item.Settings#maxCount` to any number below `int_max/2`!~~
7+
~~As of June 3rd 2021, Stacc is now **only** an 'api' mod.~~
68

7-
As of June 3rd 2021, Stacc is now **only** an 'api' mod.
8-
To use it, simply configure your item to have a max stack size of greater than 64. (Item$Settings#maxCount)
9-
It is not recommended setting the stack size greater than int_max/2 (1,073,741,823).
9+
As of January 30th, 2023 (version 1.5.0), Stacc now includes what was previously the mod in the API. To use it, create a `data/stacc/config.json` of the following format:
10+
```json5
11+
{
12+
"item:id": 300,
13+
// if a lower priority resource pack changed the item count, you can change it back with 'default'
14+
"minecraft:item": "default",
15+
"minecraft:other_item": 1,
16+
// max supported stack size is 1 billion
17+
"minecraft:really_smol_item": 1000000000
18+
}
19+
```
20+
21+
# API
22+
To use it, simply configure your item to have a max stack size of greater than 64. (`Item$Settings#maxCount`)
23+
It is not recommended setting the stack size greater than int_max/2 (1,073,741,823)
24+
- 1 billion is recommended to be safe.
25+
- 536,870,912 is the safest power of two (to stick by Minecraft's conventions)
1026

1127
gradle:
1228
```groovy
@@ -20,8 +36,6 @@ repositories {
2036
2137
dependencies {
2238
// there is no api (well except for render handler), just set maxCount in Item$Settings to values over 64
23-
modRuntime("net.devtech:Stacc:1.4.0")
24-
// you should probably include() it too
25-
// modRuntime(include("net.devtech:Stacc:1.4.0"))
39+
modRuntime("net.devtech:Stacc:1.5.1") // you should probably include the api though
2640
}
2741
```

build.gradle

+37-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
id 'fabric-loom' version '0.12-SNAPSHOT'
33
id 'maven-publish'
4+
id "me.shedaniel.unified-publishing" version "0.1.+"
45
}
56

67
sourceCompatibility = JavaVersion.VERSION_17
@@ -14,6 +15,7 @@ dependencies {
1415
minecraft "com.mojang:minecraft:${project.minecraft_version}"
1516
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
1617
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
18+
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
1719
}
1820

1921
processResources {
@@ -35,13 +37,7 @@ jar {
3537
publishing {
3638
publications {
3739
mavenJava(MavenPublication) {
38-
// add all the jars that should be included when publishing to maven
39-
artifact(remapJar) {
40-
builtBy remapJar
41-
}
42-
artifact(sourcesJar) {
43-
builtBy remapSourcesJar
44-
}
40+
from(components["java"])
4541
}
4642
}
4743
// select the repositories you want to publish to
@@ -57,4 +53,38 @@ publishing {
5753
}
5854
}
5955
}
56+
}
57+
58+
File file = file("tokens.properties")
59+
if(file.exists()) {
60+
Properties properties = new Properties()
61+
try (InputStream stream = new FileInputStream(file)) {
62+
properties.load(stream)
63+
}
64+
65+
unifiedPublishing {
66+
project {
67+
gameVersions = [minecraft_version]
68+
gameLoaders = ["fabric"]
69+
70+
mainPublication tasks.remapJar
71+
//secondaryPublication tasks.remapSourcesJar
72+
73+
var cfToken = properties.getProperty("cf_token")
74+
if (cfToken != null) {
75+
curseforge {
76+
token = cfToken
77+
id = "820136"
78+
}
79+
}
80+
81+
var mrToken = properties.getProperty("mr_token")
82+
if (mrToken != null) {
83+
modrinth {
84+
token = mrToken
85+
id = "fauLGdJR"
86+
}
87+
}
88+
}
89+
}
6090
}

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Done to increase the memory available to gradle.
22
org.gradle.jvmargs=-Xmx4G
33
# Mod Properties
4-
mod_version=1.3.5
4+
mod_version=1.5.1
55
maven_group=net.devtech
66
archives_base_name=stacc
77

settings.gradle

+4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ pluginManagement {
44
name = 'Fabric'
55
url = 'https://maven.fabricmc.net/'
66
}
7+
maven {
8+
name = 'Architectury'
9+
url "https://maven.architectury.dev/"
10+
}
711
gradlePluginPortal()
812
}
913
}

src/main/java/net/devtech/stacc/StaccGlobals.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66

77
public final class StaccGlobals {
88
public static final ThreadLocal<Long> COUNT = ThreadLocal.withInitial(() -> 0L);
9-
private static int max, lastSize;
9+
static int max, lastSize;
1010

1111
private StaccGlobals() {}
1212

1313
// ideally this would use a callback, but I am lazy
1414
public static int getMax() {
1515
Registry<Item> items = Registries.ITEM;
16-
int size = items.getIds().size(), max = StaccGlobals.max;
16+
int size = items.getIds().size(), max;
1717
if (lastSize != size) {
1818
StaccGlobals.max = max = items.stream().mapToInt(Item::getMaxCount).max().orElse(0);
1919
lastSize = size;
20+
} else {
21+
max = StaccGlobals.max;
2022
}
2123
return max;
2224
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package net.devtech.stacc;
2+
3+
import com.google.gson.JsonElement;
4+
import com.google.gson.JsonObject;
5+
import com.google.gson.JsonPrimitive;
6+
import com.mojang.logging.LogUtils;
7+
import net.devtech.stacc.mixin.ItemMaxCountAccess;
8+
import net.fabricmc.api.ModInitializer;
9+
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
10+
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
11+
import net.minecraft.item.Item;
12+
import net.minecraft.item.Items;
13+
import net.minecraft.registry.Registries;
14+
import net.minecraft.resource.Resource;
15+
import net.minecraft.resource.ResourceManager;
16+
import net.minecraft.resource.ResourceType;
17+
import net.minecraft.util.Identifier;
18+
import net.minecraft.util.JsonHelper;
19+
import net.minecraft.util.profiler.Profiler;
20+
import org.slf4j.Logger;
21+
import java.io.BufferedReader;
22+
import java.io.IOException;
23+
import java.util.HashMap;
24+
import java.util.IdentityHashMap;
25+
import java.util.List;
26+
import java.util.Map;
27+
import java.util.concurrent.CompletableFuture;
28+
import java.util.concurrent.Executor;
29+
30+
public class StaccLoader implements ModInitializer {
31+
private static final Logger LOGGER = LogUtils.getLogger();
32+
public static final String MOD_ID = "stacc";
33+
34+
@Override
35+
public void onInitialize() {
36+
Map<Item, Integer> originalSizes = new IdentityHashMap<>();
37+
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new IdentifiableResourceReloadListener() {
38+
final Identifier id = id("cfg");
39+
final Identifier resourceId = id("config.json");
40+
41+
@Override
42+
public Identifier getFabricId() {
43+
return this.id;
44+
}
45+
46+
@Override
47+
public CompletableFuture<Void> reload(
48+
Synchronizer synchronizer,
49+
ResourceManager manager,
50+
Profiler prepareProfiler,
51+
Profiler applyProfiler,
52+
Executor prepareExecutor,
53+
Executor applyExecutor
54+
) {
55+
return CompletableFuture.supplyAsync(() -> {
56+
Map<Identifier, Integer> stackSizes = new HashMap<>();
57+
List<Resource> resources = manager.getAllResources(this.resourceId);
58+
for (Resource resource : resources) {
59+
try(BufferedReader reader = resource.getReader()) {
60+
JsonObject keys = JsonHelper.deserialize(reader);
61+
for (var entry : keys.entrySet()) {
62+
Identifier itemId = new Identifier(entry.getKey());
63+
JsonElement value = entry.getValue();
64+
if(value.isJsonNull()) {
65+
stackSizes.remove(itemId);
66+
} else if(value.isJsonArray() || value.isJsonObject()) {
67+
throw new IOException("Invalid stack size for %s: %s! Must be: {[0-1,000,000,000], \"default\", or null}".formatted(itemId, value));
68+
} else if(value instanceof JsonPrimitive p) {
69+
if(p.isNumber()) {
70+
int size = p.getAsNumber().intValue();
71+
if(size < 0 || size > 1_000_000_000) {
72+
throw new IOException("Invalid stack size for %s: %s! Must be: {[0-1,000,000,000], \"default\", or null}".formatted(itemId, size));
73+
} else {
74+
stackSizes.put(itemId, size);
75+
}
76+
} else if(p.isString() && p.getAsString().equals("default")) {
77+
stackSizes.remove(itemId);
78+
} else {
79+
throw new IOException("Invalid stack size for %s: %s! Must be: {[0-1,000,000,000], \"default\", or null}".formatted(itemId, value));
80+
}
81+
}
82+
}
83+
} catch (IOException e) {
84+
throw rethrow(new IOException("Invalid stack:config.json in pack \"%s\", format is {\"item:id\": 43, \"item:id2\": 5785, ...}!".formatted(resource.getPack().getName()), e));
85+
}
86+
}
87+
return stackSizes;
88+
}, prepareExecutor).thenCompose(synchronizer::whenPrepared).thenAcceptAsync(u -> {
89+
Map<Item, Integer> restore = new HashMap<>(originalSizes);
90+
for (var entry : u.entrySet()) {
91+
Identifier key = entry.getKey();
92+
Integer value = entry.getValue();
93+
Item item = Registries.ITEM.get(key);
94+
originalSizes.putIfAbsent(item, item.getMaxCount());
95+
restore.remove(item);
96+
if(item == Items.AIR) {
97+
LOGGER.warn("No item found for: %s".formatted(key));
98+
} else {
99+
int old = item.getMaxCount();
100+
((ItemMaxCountAccess)item).setMaxCount(value);
101+
LOGGER.info("Changed max count of %s from %s to %s!".formatted(key, old, value));
102+
}
103+
}
104+
restore.forEach((item, originalCount) -> {
105+
((ItemMaxCountAccess) item).setMaxCount(originalCount);
106+
originalSizes.remove(item);
107+
});
108+
StaccGlobals.lastSize = -1;
109+
}, applyExecutor);
110+
}
111+
});
112+
}
113+
114+
public static Identifier id(String path) {
115+
return new Identifier(MOD_ID, path);
116+
}
117+
118+
/**
119+
* @return nothing, because it throws
120+
* @throws T rethrows {@code throwable}
121+
*/
122+
@SuppressWarnings("unchecked")
123+
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
124+
throw (T) throwable;
125+
}
126+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package net.devtech.stacc.mixin;
2+
3+
import net.minecraft.item.Item;
4+
import org.spongepowered.asm.mixin.Mixin;
5+
import org.spongepowered.asm.mixin.Mutable;
6+
import org.spongepowered.asm.mixin.gen.Accessor;
7+
8+
@Mixin (Item.class)
9+
public interface ItemMaxCountAccess {
10+
@Mutable
11+
@Accessor
12+
void setMaxCount(int maxCount);
13+
}
771 Bytes
Loading

src/main/resources/fabric.mod.json

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
"id": "stacc",
44
"version": "${version}",
55
"name": "Stacc",
6+
"description": "An library mod that allows developers and modpack authors to make items with >64 stack size",
67
"license": "CC0-1.0",
7-
"icon": "assets/stacc/icon.png",
88
"environment": "*",
9+
"icon": "assets/stacc/icon.png",
910
"mixins": [
1011
"stacc.mixins.json"
11-
]
12+
],
13+
"entrypoints": {
14+
"main": [
15+
"net.devtech.stacc.StaccLoader"
16+
]
17+
}
1218
}

src/main/resources/stacc.mixins.json

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"DesktopHandSplayedDuplicationFixin",
1212
"DesyncFixin",
1313
"InventoryMixin",
14+
"ItemMaxCountAccess",
1415
"OOMFixin",
1516
"PlayerInventoryMixin",
1617
"SerializationFixin"

0 commit comments

Comments
 (0)