Skip to content

Commit

Permalink
feat: Backport Aversion Obelisk and Soul Filters
Browse files Browse the repository at this point in the history
Thanks a lot to krxdev-kaan for backporting these features!
  • Loading branch information
krxdev-kaan authored Oct 1, 2024
1 parent d26fb4c commit 75bb8b2
Show file tree
Hide file tree
Showing 41 changed files with 1,493 additions and 4 deletions.
11 changes: 11 additions & 0 deletions src/api/java/com/enderio/api/filter/EntityFilter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.enderio.api.filter;

import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;

import java.util.function.Predicate;

public interface EntityFilter extends ResourceFilter, Predicate<Entity> {

boolean test(EntityType<?> entity);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.enderio.core.common.capability;

import com.enderio.api.capability.StoredEntityData;
import com.enderio.api.filter.EntityFilter;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.ItemStack;

import java.util.ArrayList;
import java.util.List;

public class EntityFilterCapability implements IFilterCapability<StoredEntityData>, EntityFilter {

private static final String NBT_KEY = "IsNbt";
private static final String INVERTED_KEY = "IsInverted";
private static final String ENTRIES_KEY = "EntityEntries";

private final ItemStack container;
private final int size;

public EntityFilterCapability(ItemStack container, int size) {
this.container = container;
this.size = size;

CompoundTag tag = container.getOrCreateTag();
if (!tag.contains(ENTRIES_KEY, CompoundTag.TAG_LIST)) {
ListTag entriesList = new ListTag();
for (int i = 0; i < size; i++) {
entriesList.add(StoredEntityData.empty().serializeNBT());
}
tag.put(ENTRIES_KEY, entriesList);
}
}

@Override
public void setNbt(Boolean nbt) {
CompoundTag tag = container.getOrCreateTag();
tag.putBoolean(NBT_KEY, nbt);
}

@Override
public boolean isNbt() {
CompoundTag tag = container.getOrCreateTag();
return tag.contains(NBT_KEY, CompoundTag.TAG_BYTE) && tag.getBoolean(NBT_KEY);
}

@Override
public void setInverted(Boolean inverted) {
CompoundTag tag = container.getOrCreateTag();
tag.putBoolean(INVERTED_KEY, inverted);
}

@Override
public boolean isInvert() {
CompoundTag tag = container.getOrCreateTag();
return tag.contains(INVERTED_KEY, CompoundTag.TAG_BYTE) && tag.getBoolean(INVERTED_KEY);
}

@Override
public int size() {
return size;
}

@Override
public List<StoredEntityData> getEntries() {
CompoundTag tag = container.getOrCreateTag();

List<StoredEntityData> entries = new ArrayList<>();
if (tag.contains(ENTRIES_KEY, CompoundTag.TAG_LIST)) {
ListTag entriesList = tag.getList(ENTRIES_KEY, CompoundTag.TAG_COMPOUND);
for (var entry : entriesList) {
StoredEntityData entityData = StoredEntityData.empty();
entityData.deserializeNBT(entry);
entries.add(entityData);
}
}

return entries;
}

@Override
public StoredEntityData getEntry(int index) {
CompoundTag tag = container.getOrCreateTag();

if (!tag.contains(ENTRIES_KEY, CompoundTag.TAG_LIST)) {
return StoredEntityData.empty();
}

ListTag entriesList = tag.getList(ENTRIES_KEY, CompoundTag.TAG_COMPOUND);
StoredEntityData entityData = StoredEntityData.empty();
entityData.deserializeNBT(entriesList.get(index));
return entityData;
}

@Override
public void setEntry(int index, StoredEntityData entry) {
CompoundTag tag = container.getOrCreateTag();

ListTag entriesList;
if (tag.contains(ENTRIES_KEY, CompoundTag.TAG_LIST)) {
entriesList = tag.getList(ENTRIES_KEY, CompoundTag.TAG_COMPOUND);
} else {
entriesList = new ListTag();
tag.put(ENTRIES_KEY, entriesList);
}

entriesList.set(index, entry.serializeNBT());
}

@Override
public boolean test(Entity entity) {
boolean typematch = test(entity.getType());
if (isNbt()) {
for (StoredEntityData entry : getEntries()) {
CompoundTag tag = entity.serializeNBT();
boolean test = tag.equals(entry.getEntityTag());
if (test) {
return !isInvert() && typematch;
}
}
}

return typematch;
}

@Override
public boolean test(EntityType<?> entity) {
for (StoredEntityData entry : getEntries()) {
ResourceLocation key = BuiltInRegistries.ENTITY_TYPE.getKey(entity);
if (entry.getEntityType().isPresent() && entry.getEntityType().get().equals(key)) {
return !isInvert();
}
}
return isInvert();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import java.util.List;
import java.util.function.Predicate;

public interface IFilterCapability<T> extends Predicate<T> {
public interface IFilterCapability<T> {

void setNbt(Boolean nbt);

Expand Down
164 changes: 164 additions & 0 deletions src/core/java/com/enderio/core/common/util/ChunkBoundLookup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.enderio.core.common.util;

import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ChunkPos;
import org.jetbrains.annotations.Nullable;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
* Implements the concept of a spatial hashmap, bucketed by chunk.
*/
public class ChunkBoundLookup<T> {
private final Long2ObjectMap<Set<T>> chunkData = new Long2ObjectOpenHashMap<>();
private final Reference2ObjectMap<T, Set<ChunkPos>> valueKeys = new Reference2ObjectOpenHashMap<>();

@Nullable
public Set<T> getForChunk(ChunkPos pos) {
return chunkData.get(pos.toLong());
}

// region Direct Chunk Manipulation

/**
* Adds a value to a chunk in the lookup.
*
* @param pos The chunk to be added to.
* @param value The value to add.
*/
public void addToChunk(ChunkPos pos, T value) {
chunkData.computeIfAbsent(pos.toLong(), k -> new HashSet<>()).add(value);
valueKeys.computeIfAbsent(value, k -> new HashSet<>()).add(pos);
}

/**
* Remove a value from a chunk in the lookup.
*
* @param pos The chunk to be removed from.
* @param value The value to remove.
*/
public void removeFromChunk(ChunkPos pos, T value) {
if (chunkData.containsKey(pos.toLong())) {
chunkData.get(pos.toLong()).remove(value);
}

if (valueKeys.containsKey(value)) {
valueKeys.get(value).remove(pos);
}
}

// endregion

// region Chunk and Block Ranges

/**
* Add the given value to the lookup with the given center point and square radius.
*
* @param centerPos The center block position of the range.
* @param blockRadius The radius (in blocks) of the range.
* @param value The value to add.
*/
public void addForBlockRadius(BlockPos centerPos, int blockRadius, T value) {
getBlockRadius(centerPos, blockRadius).forEach(chunkPos -> addToChunk(chunkPos, value));
}

/**
* Update the center position and radius of an existing entry efficiently.
* Instead of removing from all chunks then adding to all chunks, this only adds and removes the differences.
* If the item does not yet exist, behaves the same as addForBlockRadius.
*
* @param centerPos The center block position of the range.
* @param blockRadius The radius (in blocks) of the range.
* @param value The value to update.
*/
public void updateForBlockRadius(BlockPos centerPos, int blockRadius, T value) {
Set<ChunkPos> currentChunks = valueKeys.get(value);
if (currentChunks == null) {
addForBlockRadius(centerPos, blockRadius, value);
return;
}

Set<ChunkPos> newChunks = getBlockRadius(centerPos, blockRadius).collect(Collectors.toSet());
bulkUpdate(value, currentChunks, newChunks);
}

/**
* Add the given value to the lookup with the given center point and square radius.
*
* @param centerPos The center chunk position of the range.
* @param chunkRadius The radius (in chunks) of the range.
* @param value The value to add.
*/
public void addForChunkRadius(ChunkPos centerPos, int chunkRadius, T value) {
ChunkPos.rangeClosed(centerPos, chunkRadius).forEach(chunkPos -> addToChunk(chunkPos, value));
}

/**
* Update the center position and radius of an existing entry efficiently.
* Instead of removing from all chunks then adding to all chunks, this only adds and removes the differences.
* If the item does not yet exist, behaves the same as addForBlockRadius.
*
* @param centerPos The center chunk position of the range.
* @param chunkRadius The radius (in chunks) of the range.
* @param value The value to update.
*/
public void updateForChunkRadius(ChunkPos centerPos, int chunkRadius, T value) {
Set<ChunkPos> currentChunks = valueKeys.get(value);
if (currentChunks == null) {
addForChunkRadius(centerPos, chunkRadius, value);
return;
}

Set<ChunkPos> newChunks = ChunkPos.rangeClosed(centerPos, chunkRadius).collect(Collectors.toSet());
bulkUpdate(value, currentChunks, newChunks);
}

private Stream<ChunkPos> getBlockRadius(BlockPos centerPos, int blockRadius) {
BlockPos startBlockPos = new BlockPos(centerPos.getX() - blockRadius, 0, centerPos.getZ() - blockRadius);
BlockPos endBlockPos = new BlockPos(centerPos.getX() + blockRadius, 0, centerPos.getZ() + blockRadius);

ChunkPos startChunkPos = new ChunkPos(startBlockPos);
ChunkPos endChunkPos = new ChunkPos(endBlockPos);

return ChunkPos.rangeClosed(startChunkPos, endChunkPos);
}

private void bulkUpdate(T value, Set<ChunkPos> chunksBefore, Set<ChunkPos> chunksAfter) {
Sets.SetView<ChunkPos> removedChunks = Sets.difference(chunksBefore, chunksAfter);
Sets.SetView<ChunkPos> addedChunks = Sets.difference(chunksAfter, chunksBefore);

removedChunks.forEach(chunkPos -> removeFromChunk(chunkPos, value));
addedChunks.forEach(chunkPos -> addToChunk(chunkPos, value));
}

// endregion

/**
* Remove all instances of this value from the lookup.
*
* @param value The value to remove.
*/
public void remove(T value) {
Set<ChunkPos> chunks = valueKeys.get(value);
for (ChunkPos chunkPos : chunks) {
Set<T> dataAtChunk = chunkData.get(chunkPos.toLong());

if (dataAtChunk != null) {
dataAtChunk.remove(value);
if (dataAtChunk.isEmpty()) {
chunkData.remove(chunkPos.toLong());
}
}
}

valueKeys.remove(value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "enderio:block/aversion_obelisk"
}
}
}
2 changes: 2 additions & 0 deletions src/generated/resources/assets/enderio/lang/en_ud.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"advancements.enderio.use_glider.title": "ɔıʇsǝظɐW",
"block.enderio.advanced_capacitor_bank": "ʞuɐᗺ ɹoʇıɔɐdɐƆ pǝɔuɐʌpⱯ",
"block.enderio.alloy_smelter": "ɹǝʇןǝɯS ʎoןןⱯ",
"block.enderio.aversion_obelisk": "ʞsıןǝqO uoısɹǝʌⱯ",
"block.enderio.basic_capacitor_bank": "ʞuɐᗺ ɹoʇıɔɐdɐƆ ɔısɐᗺ",
"block.enderio.clear_glass": "ssɐן⅁ ɹɐǝןƆ",
"block.enderio.clear_glass_black": "ssɐן⅁ ɹɐǝןƆ ʞɔɐןᗺ",
Expand Down Expand Up @@ -376,6 +377,7 @@
"item.enderio.energized_gear": "ɹɐǝ⅁ ןɐʇǝɯıᗺ pǝzıbɹǝuƎ",
"item.enderio.energy_conduit": "ʇınpuoƆ ʎbɹǝuƎ",
"item.enderio.enticing_crystal": "ןɐʇsʎɹƆ buıɔıʇuƎ",
"item.enderio.entity_filter": "ɹǝʇןıℲ ןnoS",
"item.enderio.experience_rod": "poᴚ ǝɔuǝıɹǝdxƎ",
"item.enderio.extraction_speed_upgrade_1": "ǝpɐɹbd∩ pǝǝdS uoıʇɔɐɹʇxƎ Ɩ ɹǝı⟘",
"item.enderio.extraction_speed_upgrade_2": "ǝpɐɹbd∩ pǝǝdS uoıʇɔɐɹʇxƎ ᄅ ɹǝı⟘",
Expand Down
2 changes: 2 additions & 0 deletions src/generated/resources/assets/enderio/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"advancements.enderio.use_glider.title": "Majestic",
"block.enderio.advanced_capacitor_bank": "Advanced Capacitor Bank",
"block.enderio.alloy_smelter": "Alloy Smelter",
"block.enderio.aversion_obelisk": "Aversion Obelisk",
"block.enderio.basic_capacitor_bank": "Basic Capacitor Bank",
"block.enderio.clear_glass": "Clear Glass",
"block.enderio.clear_glass_black": "Black Clear Glass",
Expand Down Expand Up @@ -376,6 +377,7 @@
"item.enderio.energized_gear": "Energized Bimetal Gear",
"item.enderio.energy_conduit": "Energy Conduit",
"item.enderio.enticing_crystal": "Enticing Crystal",
"item.enderio.entity_filter": "Soul Filter",
"item.enderio.experience_rod": "Experience Rod",
"item.enderio.extraction_speed_upgrade_1": "Tier 1 Extraction Speed Upgrade",
"item.enderio.extraction_speed_upgrade_2": "Tier 2 Extraction Speed Upgrade",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"parent": "enderio:block/aversion_obelisk"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "enderio:item/entity_filter"
}
}
Loading

0 comments on commit 75bb8b2

Please sign in to comment.