Skip to content

Commit

Permalink
Support custom data on chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
aromaa committed Dec 7, 2023
1 parent 2445188 commit bec886c
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import org.spongepowered.api.data.persistence.DataContainer;
import org.spongepowered.api.data.persistence.DataView;
import org.spongepowered.api.data.persistence.InvalidDataException;
import org.spongepowered.api.data.value.CollectionValue;
import org.spongepowered.api.data.value.MapValue;
import org.spongepowered.api.data.value.MergeFunction;
import org.spongepowered.api.data.value.Value;
import org.spongepowered.api.data.value.ValueContainer;
Expand Down Expand Up @@ -63,6 +65,7 @@

import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -365,4 +368,119 @@ public ScheduledUpdateList<BlockType> scheduledBlockUpdates() {
public ScheduledUpdateList<FluidType> scheduledFluidUpdates() {
throw this.emptyChunkError();
}

@Override
public <E> DataTransactionResult offer(Key<? extends Value<E>> key, E value) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult offer(Value<?> value) {
return DataTransactionResult.failNoData();
}

@Override
public <E> DataTransactionResult offerSingle(Key<? extends CollectionValue<E, ?>> key, E element) {
return DataTransactionResult.failNoData();
}

@Override
public <K, V> DataTransactionResult offerSingle(Key<? extends MapValue<K, V>> key, K valueKey, V value) {
return DataTransactionResult.failNoData();
}

@Override
public <K, V> DataTransactionResult offerAll(Key<? extends MapValue<K, V>> key, Map<? extends K, ? extends V> map) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult offerAll(MapValue<?, ?> value) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult offerAll(CollectionValue<?, ?> value) {
return DataTransactionResult.failNoData();
}

@Override
public <E> DataTransactionResult offerAll(Key<? extends CollectionValue<E, ?>> key, Collection<? extends E> elements) {
return DataTransactionResult.failNoData();
}

@Override
public <E> DataTransactionResult removeSingle(Key<? extends CollectionValue<E, ?>> key, E element) {
return DataTransactionResult.failNoData();
}

@Override
public <K> DataTransactionResult removeKey(Key<? extends MapValue<K, ?>> key, K mapKey) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult removeAll(CollectionValue<?, ?> value) {
return DataTransactionResult.failNoData();
}

@Override
public <E> DataTransactionResult removeAll(Key<? extends CollectionValue<E, ?>> key, Collection<? extends E> elements) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult removeAll(MapValue<?, ?> value) {
return DataTransactionResult.failNoData();
}

@Override
public <K, V> DataTransactionResult removeAll(Key<? extends MapValue<K, V>> key, Map<? extends K, ? extends V> map) {
return DataTransactionResult.failNoData();
}

@Override
public <E> DataTransactionResult tryOffer(Key<? extends Value<E>> key, E value) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult remove(Key<?> key) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult undo(DataTransactionResult result) {
return DataTransactionResult.failNoData();
}

@Override
public DataTransactionResult copyFrom(ValueContainer that, MergeFunction function) {
return DataTransactionResult.failNoData();
}

@Override
public <E> Optional<E> get(Key<? extends Value<E>> key) {
return Optional.empty();
}

@Override
public <E, V extends Value<E>> Optional<V> getValue(Key<V> key) {
return Optional.empty();
}

@Override
public boolean supports(Key<?> key) {
return false;
}

@Override
public Set<Key<?>> getKeys() {
return Collections.emptySet();
}

@Override
public Set<Value.Immutable<?>> getValues() {
return Collections.emptySet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import org.spongepowered.api.data.DataHolder;
import org.spongepowered.api.data.DataManipulator;
Expand All @@ -52,7 +53,8 @@
SpongeEntitySnapshot.class,
SpongeBlockSnapshot.class,
SimpleNBTDataHolder.class,
MapItemSavedData.class})
MapItemSavedData.class,
LevelChunk.class})
public abstract class SpongeDataHolderMixin implements SpongeDataHolderBridge {

private DataManipulator.Mutable impl$manipulator;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* This file is part of Sponge, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.common.mixin.core.world.level.chunk;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import org.spongepowered.common.bridge.data.DataCompoundHolder;
import org.spongepowered.common.data.DataUtil;

@Mixin(ChunkSerializer.class)
public abstract class ChunkSerializerMixin {

@Inject(method = "write", at = @At(value = "RETURN"))
private static void impl$writeSpongeChunkData(final ServerLevel level, final ChunkAccess chunk, final CallbackInfoReturnable<CompoundTag> cir) {
if (!(chunk instanceof LevelChunk)) {
return;
}

final CompoundTag compound = cir.getReturnValue();
if (DataUtil.syncDataToTag(chunk)) {
compound.merge(((DataCompoundHolder) chunk).data$getCompound());
}
}

@Inject(method = "read", at = @At("RETURN"))
private static void impl$readSpongeChunkData(final ServerLevel level, final PoiManager poi, final ChunkPos pos, final CompoundTag compound, final CallbackInfoReturnable<ProtoChunk> cir) {
if (!(cir.getReturnValue() instanceof ImposterProtoChunk imposter)) {
return;
}

((DataCompoundHolder) imposter.getWrapped()).data$setCompound(compound);
DataUtil.syncTagToData(imposter.getWrapped());
((DataCompoundHolder) imposter.getWrapped()).data$setCompound(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.base.MoreObjects;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
Expand All @@ -41,7 +42,11 @@
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.ticks.LevelChunkTicks;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.data.DataTransactionResult;
import org.spongepowered.api.data.Key;
import org.spongepowered.api.data.value.Value;
import org.spongepowered.api.util.Direction;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -52,10 +57,14 @@
import org.spongepowered.common.accessor.server.level.ChunkMapAccessor;
import org.spongepowered.common.applaunch.config.core.SpongeConfigs;
import org.spongepowered.common.bridge.CreatorTrackedBridge;
import org.spongepowered.common.bridge.data.DataCompoundHolder;
import org.spongepowered.common.bridge.data.DataHolderProcessor;
import org.spongepowered.common.bridge.data.SpongeDataHolderBridge;
import org.spongepowered.common.bridge.world.level.LevelBridge;
import org.spongepowered.common.bridge.world.level.chunk.CacheKeyBridge;
import org.spongepowered.common.bridge.world.level.chunk.LevelChunkBridge;
import org.spongepowered.common.bridge.world.level.storage.PrimaryLevelDataBridge;
import org.spongepowered.common.data.holder.SpongeMutableDataHolder;
import org.spongepowered.common.entity.PlayerTracker;
import org.spongepowered.common.event.tracking.PhaseTracker;
import org.spongepowered.common.util.Constants;
Expand All @@ -73,7 +82,7 @@
import java.util.function.Function;

@Mixin(net.minecraft.world.level.chunk.LevelChunk.class)
public abstract class LevelChunkMixin extends ChunkAccess implements LevelChunkBridge, CacheKeyBridge {
public abstract class LevelChunkMixin extends ChunkAccess implements LevelChunkBridge, CacheKeyBridge, SpongeMutableDataHolder, SpongeDataHolderBridge, DataCompoundHolder {

// @formatter:off
@Shadow @Final private Level level;
Expand All @@ -91,6 +100,7 @@ public abstract class LevelChunkMixin extends ChunkAccess implements LevelChunkB
private long impl$cacheKey;
private Map<Integer, PlayerTracker> impl$trackedIntBlockPositions = new HashMap<>();
private Map<Short, PlayerTracker> impl$trackedShortBlockPositions = new HashMap<>();
private @Nullable CompoundTag impl$compound;

public LevelChunkMixin(
final ChunkPos $$0,
Expand Down Expand Up @@ -374,4 +384,29 @@ public String toString() {
return false;
}

@Override
public CompoundTag data$getCompound() {
return this.impl$compound;
}

@Override
public void data$setCompound(final CompoundTag nbt) {
this.impl$compound = nbt;
}


@Override
public <E> DataTransactionResult bridge$offer(final Key<@NonNull ? extends Value<E>> key, final E value) {
final DataTransactionResult result = DataHolderProcessor.bridge$offer(this, key, value);
this.unsaved = true;
return result;
}

@Override
public <E> DataTransactionResult bridge$remove(final Key<@NonNull ? extends Value<E>> key) {
final DataTransactionResult result = DataHolderProcessor.bridge$remove(this, key);
this.unsaved = true;
return result;
}

}
1 change: 1 addition & 0 deletions src/mixins/resources/mixins.sponge.core.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@
"world.level.block.state.BlockStateMixin",
"world.level.border.WorldBorderMixin",
"world.level.chunk.ChunkGeneratorMixin",
"world.level.chunk.ChunkSerializerMixin",
"world.level.chunk.LevelChunkMixin",
"world.level.chunk.storage.IOWorkerMixin",
"world.level.dimension.DimensionTypeMixin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.scheduler.Task;
import org.spongepowered.api.util.Ticks;
import org.spongepowered.api.world.chunk.WorldChunk;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.math.vector.Vector3i;
import org.spongepowered.plugin.PluginContainer;
Expand Down Expand Up @@ -97,7 +98,8 @@ private enum Type {
BLOCKENTITY,
PLAYER,
USER,
BLOCK
BLOCK,
CHUNK
}

@Listener
Expand Down Expand Up @@ -157,6 +159,12 @@ private void onRegisterSpongeCommand(final RegisterCommandEvent<Command.Paramete
final Integer oldNumber = player.world().get(player.blockPosition(), this.myDataKey).orElse(0);
player.sendActionBar(Component.text(oldNumber));
player.world().offer(player.blockPosition(), this.myDataKey, oldNumber + number);
break;
case CHUNK:
final Integer oldNumber2 = player.world().chunk(player.location().chunkPosition()).get(this.myDataKey).orElse(0);
player.sendActionBar(Component.text(oldNumber2));
player.world().chunk(player.location().chunkPosition()).offer(this.myDataKey, oldNumber2 + number);
break;
}
return CommandResult.success();
})
Expand All @@ -175,7 +183,7 @@ private void onRegisterData(final RegisterDataEvent event) {
.build();


final DataStore dataStore = DataStore.of(this.myDataKey, DataQuery.of("mykey"), ItemStack.class, User.class, ServerPlayer.class, BlockEntity.class, Entity.class);
final DataStore dataStore = DataStore.of(this.myDataKey, DataQuery.of("mykey"), ItemStack.class, User.class, ServerPlayer.class, BlockEntity.class, Entity.class, WorldChunk.class);
final DataRegistration myRegistration = DataRegistration.builder()
.dataKey(this.myDataKey)
.store(dataStore)
Expand Down

0 comments on commit bec886c

Please sign in to comment.