Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smarter Registry System #26

Merged
merged 5 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions src/main/java/turniplabs/halplibe/helper/BlockHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@
import net.minecraft.core.item.Item;
import net.minecraft.core.item.block.ItemBlock;
import turniplabs.halplibe.mixin.accessors.BlockAccessor;
import turniplabs.halplibe.util.registry.IdSupplier;
import turniplabs.halplibe.util.registry.RunLengthConfig;
import turniplabs.halplibe.util.registry.RunReserves;
import turniplabs.halplibe.util.toml.Toml;

import java.util.ArrayList;
import java.util.function.Consumer;

@Deprecated
public class BlockHelper {

public static int highestVanilla;


private static final RunReserves reserves = new RunReserves(
BlockHelper::findOpenIds,
BlockHelper::findLength
);

/**
* Should be called in a runnable scheduled with {@link RegistryHelper#scheduleRegistry(boolean, Runnable)}
* @param count the amount of needed blocks for the mod
Expand All @@ -22,7 +30,7 @@ public class BlockHelper {
public static int findOpenIds(int count) {
int run = 0;
for (int i = highestVanilla; i < Block.blocksList.length; i++) {
if (Block.blocksList[i] == null) {
if (Block.blocksList[i] == null && !reserves.isReserved(i)) {
if (run >= count)
return (i - run);
run++;
Expand All @@ -32,6 +40,39 @@ public static int findOpenIds(int count) {
}
return -1;
}

public static int findLength(int id, int terminate) {
int run = 0;
for (int i = id; i < Block.blocksList.length; i++) {
if (Block.blocksList[i] == null && !reserves.isReserved(i)) {
run++;
if (run >= terminate) return terminate;
} else {
return run;
}
}
return run;
}

/**
* Allows halplibe to automatically figure out where to insert the runs
* @param modid an identifier for the mod, can be anything, but should be something the user can identify
* @param runs a toml object representing configured registry runs
* @param neededIds the number of needed ids
* if this changes after the mod has been configured (i.e. mod updated and now has more blocks) it'll find new, valid runs to put those blocks into
* @param function the function to run for registering items
*/
public static void reserveRuns(String modid, Toml runs, int neededIds, Consumer<IdSupplier> function) {
RunLengthConfig cfg = new RunLengthConfig(runs, neededIds);
cfg.register(reserves);
RegistryHelper.scheduleSmartRegistry(
() -> {
IdSupplier supplier = new IdSupplier(modid, reserves, cfg, neededIds);
function.accept(supplier);
supplier.validate();
}
);
}

@Deprecated
public static Block createBlock(String modId, Block block, String texture, BlockSound stepSound, float hardness, float resistance, float lightValue) {
Expand Down
50 changes: 47 additions & 3 deletions src/main/java/turniplabs/halplibe/helper/ItemHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@
import net.minecraft.core.item.Item;
import turniplabs.halplibe.HalpLibe;
import turniplabs.halplibe.mixin.mixins.registry.BlockMixin;
import turniplabs.halplibe.util.registry.IdSupplier;
import turniplabs.halplibe.util.registry.RunLengthConfig;
import turniplabs.halplibe.util.registry.RunReserves;
import turniplabs.halplibe.util.toml.Toml;

import java.util.function.Consumer;

public class ItemHelper {

public static int highestVanilla;


private static final RunReserves reserves = new RunReserves(
ItemHelper::findOpenIds,
ItemHelper::findLength
);

/**
* Should be called in a runnable scheduled with {@link RegistryHelper#scheduleRegistry(boolean, Runnable)}
* @param count the amount of needed blocks for the mod
Expand All @@ -20,7 +31,7 @@ public static int findOpenIds(int count) {
// block ids should always match the id of their corresponding item
// therefor, start registering items one after the max block id
for (int i = Block.blocksList.length + 1; i < Item.itemsList.length; i++) {
if (Item.itemsList[i] == null) {
if (Item.itemsList[i] == null && !reserves.isReserved(i)) {
if (run >= count)
return (i - run);
run++;
Expand All @@ -30,7 +41,40 @@ public static int findOpenIds(int count) {
}
return -1;
}


public static int findLength(int id, int terminate) {
int run = 0;
for (int i = id; i < Item.itemsList.length; i++) {
if (Item.itemsList[i] == null && !reserves.isReserved(i)) {
run++;
if (run >= terminate) return terminate;
} else {
return run;
}
}
return run;
}

/**
* Allows halplibe to automatically figure out where to insert the runs
* @param modid an identifier for the mod, can be anything, but should be something the user can identify
* @param runs a toml object representing configured registry runs
* @param neededIds the number of needed ids
* if this changes after the mod has been configured (i.e. mod updated and now has more items) it'll find new, valid runs to put those items into
* @param function the function to run for registering items
*/
public static void reserveRuns(String modid, Toml runs, int neededIds, Consumer<IdSupplier> function) {
RunLengthConfig cfg = new RunLengthConfig(runs, neededIds);
cfg.register(reserves);
RegistryHelper.scheduleSmartRegistry(
() -> {
IdSupplier supplier = new IdSupplier(modid, reserves, cfg, neededIds);
function.accept(supplier);
supplier.validate();
}
);
}

public static Item createItem(String modId, Item item, String translationKey, String texture) {
int[] mainCoords = TextureHelper.getOrCreateItemTexture(modId, texture);
item.setIconCoord(mainCoords[0], mainCoords[1]);
Expand Down
36 changes: 31 additions & 5 deletions src/main/java/turniplabs/halplibe/helper/RegistryHelper.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
package turniplabs.halplibe.helper;

import turniplabs.halplibe.util.toml.Toml;

import java.util.ArrayList;
import java.util.function.Consumer;

public class RegistryHelper {
private static final ArrayList<Runnable> regsitryFunctions = new ArrayList<>();

private static final ArrayList<Runnable> configuredRegsitryFunctions = new ArrayList<>();
private static final ArrayList<Runnable> smartRregsitryFunctions = new ArrayList<>();

/**
* Only intended for internal use from {@link BlockHelper#reserveRuns(Toml, int, Consumer)} and {@link ItemHelper#reserveRuns(Toml, int, Consumer)}
*
*
* @param function the function to run on registry handling
*/
public static void scheduleSmartRegistry(Runnable function) {
smartRregsitryFunctions.add(function);
}

/**
* For blocks and items, use {@link BlockHelper#reserveRuns(Toml, int, Consumer)} and {@link ItemHelper#reserveRuns(Toml, int, Consumer)}, respectively
* These will figure out what ids are available automatically, making sure to account for mods that aren't using halplibe, or are using {@link RegistryHelper#scheduleRegistry(boolean, Runnable)}
*
* Reason this is not deprecated:
* - other registries that halplibe doesn't already have utils for
* - mods that already have their item count fully defined from the start (i.e. some mod author already knows they will only ever have 2 items)
*
* @param configured if the mod has already been configured in the past
* @param function the function to run upon registering stuff
*/
public static void scheduleRegistry(boolean configured, Runnable function) {
if (configured) regsitryFunctions.add(0, function);
if (configured) configuredRegsitryFunctions.add(function);
else regsitryFunctions.add(function);
}

@SuppressWarnings("unused")
private static void runRegistry() {
for (Runnable regsitryFunction : regsitryFunctions) {
regsitryFunction.run();
}
for (Runnable regsitryFunction : configuredRegsitryFunctions) regsitryFunction.run();
for (Runnable regsitryFunction : smartRregsitryFunctions) regsitryFunction.run();
for (Runnable regsitryFunction : regsitryFunctions) regsitryFunction.run();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package turniplabs.halplibe.mixin.mixins.registry;

import net.minecraft.core.block.Block;
import net.minecraft.core.block.material.Material;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
Expand All @@ -9,15 +10,25 @@
import turniplabs.halplibe.helper.BlockHelper;

@Mixin(value = Block.class, remap = false)
public class BlockMixin {
public abstract class BlockMixin {
@Shadow public static int highestBlockId;

@Shadow @Final public int id;


@Shadow @Final public static Block[] blocksList;

@Shadow public abstract String getKey();

@Inject(at = @At("TAIL"), method = "<clinit>")
private static void captureHighest(CallbackInfo ci) {
BlockHelper.highestVanilla = highestBlockId;
}

@Inject(at = @At(value = "INVOKE", target = "Ljava/lang/IllegalArgumentException;<init>(Ljava/lang/String;)V", shift = At.Shift.BEFORE), method = "<init>")
public void addInfo(String key, int id, Material material, CallbackInfo ci) {
throw new IllegalArgumentException("Slot " + id + " is already occupied by " + blocksList[id].getKey() + " when adding " + key);
}

@Redirect(method = "<clinit>", at = @At(value = "INVOKE", target = "Lnet/minecraft/core/achievement/stat/StatList;onBlockInit()V"))
private static void delayInit() {
}
Expand Down
28 changes: 24 additions & 4 deletions src/main/java/turniplabs/halplibe/util/TomlConfigHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class TomlConfigHandler {
private static final String CONFIG_DIRECTORY = FabricLoader.getInstance().getGameDir().toString() + "/config/";
private final Toml defaults;
private final Toml config;
private Toml rawParsed;
private String configFileName = "";

private ConfigUpdater updater;
Expand Down Expand Up @@ -86,10 +87,15 @@ public void writeConfig() {

// make sure the actual config has all the required entries
config.merge(defaults);
if (rawParsed != null) {
// preserve undefined entries
// used due to run config handler
rawParsed.merge(true, config);
} else rawParsed = config;

// write the config
try (OutputStream output = new FileOutputStream(configFile)) {
output.write(config.toString().getBytes());
output.write(rawParsed.toString().getBytes());
output.close();
} catch (IOException e) {
e.printStackTrace();
Expand All @@ -115,13 +121,27 @@ private void loadConfig(File configFile, Toml properties) {
}

Toml parsed = TomlParser.parse(baos.toString());
updater.updating = parsed;
updater.update();
properties.merge(true, parsed);

// TODO: system for specifying "greedy" categories?
// greedy categories would keep all entries that aren't sepcified in code but are specified in the config
if (defaults.getComment().isPresent()) {
rawParsed = new Toml(defaults.getComment().get());
rawParsed.addMissing(parsed);
} else rawParsed = parsed;

if (updater != null) {
updater.updating = rawParsed;
updater.update();
}
properties.merge(true, rawParsed);

input.close();
} catch (IOException e) {
e.printStackTrace();
}
}

public Toml getRawParsed() {
return rawParsed;
}
}
Loading
Loading