Api data problème


#1

Bonjour
j’ai un petit problème avec l’api Data. Je ne suis pas un professionnel du java^^.

Je sauvegarde un Vector3d, mais au redémarrage du serveur les données sont écraser et valent (0,0,0) à cause de la méthode create().
Comment je peux faire pour ne pas les réinitialiser ?

Le Code
import com.flowpowered.math.vector.Vector3d;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.block.BlockState;
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataHolder;
import org.spongepowered.api.data.DataView;
import org.spongepowered.api.data.key.Key;
import org.spongepowered.api.data.manipulator.DataManipulatorBuilder;
import org.spongepowered.api.data.manipulator.immutable.common.AbstractImmutableSingleData;
import org.spongepowered.api.data.manipulator.mutable.common.AbstractSingleData;
import org.spongepowered.api.data.merge.MergeFunction;
import org.spongepowered.api.data.persistence.AbstractDataBuilder;
import org.spongepowered.api.data.persistence.InvalidDataException;
import org.spongepowered.api.data.value.BaseValue;
import org.spongepowered.api.data.value.immutable.ImmutableValue;
import org.spongepowered.api.data.value.mutable.Value;

import java.util.Optional;

public class MyVector3dData extends AbstractSingleData<Vector3d, MyVector3dData, MyVector3dData.Immutable> {

    public MyVector3dData(Vector3d value, Key<? extends Value<Vector3d>> usedKey) {
        super(usedKey, value);
    }

    @Override
    public Value<Vector3d> getValueGetter() {
        return Sponge.getRegistry().getValueFactory().createValue(ToolKeys.VECTOR3D, getValue());
    }

    public Value<Vector3d> blockstate() {
        return getValueGetter();
    }

    @Override
    public Optional<MyVector3dData> fill(DataHolder dataHolder, MergeFunction overlap) {
        Optional<MyVector3dData> data_ = dataHolder.get(MyVector3dData.class);
        if (data_.isPresent()) {
            MyVector3dData data = data_.get();
            MyVector3dData finalData = overlap.merge(this, data);
            setValue(finalData.getValue());
        }
        return Optional.of(this);
    }

    @Override
    public Optional<MyVector3dData> from(DataContainer container) {
        return Optional.of(this);
    }

    @Override
    public MyVector3dData copy() {
        return new MyVector3dData(getValue(), ToolKeys.VECTOR3D);
    }

    @Override
    public Immutable asImmutable() {
        return new Immutable(ToolKeys.VECTOR3D, getValue());
    }

    @Override
    public int getContentVersion() {
        return 1;
    }

    public class Immutable extends AbstractImmutableSingleData<Vector3d, Immutable, MyVector3dData> {

        public Immutable(Key<? extends Value<Vector3d>> usedKey, Vector3d value) {
            super(usedKey, value);
        }

        @Override
        public <E> Optional<Immutable> with(Key<? extends BaseValue<E>> key, E value) {
            if(this.supports(key)) {
                return Optional.of(asMutable().set(key, value).asImmutable());
            } else {
                return Optional.empty();
            }
        }

        @Override
        protected ImmutableValue<?> getValueGetter() {
            return Sponge.getRegistry().getValueFactory().createValue(ToolKeys.VECTOR3D, getValue()).asImmutable();
        }

        @Override
        public MyVector3dData asMutable() {
            return new MyVector3dData(getValue(), ToolKeys.VECTOR3D);
        }

        @Override
        public int getContentVersion() {
            return 1;
        }
    }
    public static class Builder extends AbstractDataBuilder<MyVector3dData> implements DataManipulatorBuilder<MyVector3dData, Immutable> {
        public Builder() {
            super(MyVector3dData.class, 1);
        }

        @Override
        public MyVector3dData create() {
            return new MyVector3dData(new Vector3d(0, 0, 0), ToolKeys.VECTOR3D);
        }

        @Override
        public Optional<MyVector3dData> createFrom(DataHolder dataHolder) {
            return create().fill(dataHolder);
        }

        @Override
        protected Optional<MyVector3dData> buildContent(DataView container) throws InvalidDataException {
            return Optional.of(create());
        }
    }
}

J’ai utiliser cet exemple:


#2

Requested from an eminent user :

Hi,
I have kind of a trouble with Data API. I am not a pro with java.

I save a Vector3D but when rebooting the server datas get erased and are set to (0,0,0) because of the create() method.

How can I do to avoid reset of datas ?

I used that example

(Mais je ne saurais pas te répondre, désolé !)


#3

There are three comments at the top saying what kind of example it is. The one you need to pay attention to is the one that says “non-persistent data” - this is data that will not persist through a server restart. The repository contains other examples, including ones that are persistent, and the difference between them is whether they override toContainer and provide a meaningful implementation in from. Look at the other examples in the project for how to do that.


#4

Je n’y arrive pas, je peux avoir un autre exemple SVP?

[Google translate]
I can not do it, can I have another example?


#5

#6

Merci ^^, j’avais mal fait la première fois que j’ai essayé l’exemple MyStandardData, maintenant cela fonctionne

[translate.google]
Thank you ^^, I had done wrong the first time I tried the MyStandardData example, now it works


#8

Bonjour,
j’ai créé une nouvelle key qui ne fonctionne pas bien , je ne comprends pas savez vous d’ou peut venir le problème ?

[translate.google.fr]
Hello,
I created a new key that does not work well, I do not understand you know where can the problem come from?

Key.builder()
public static final Key<MapValue<Integer, ItemStack>> INVENTORY = Key.builder()
        .type(new TypeToken<MapValue<Integer, ItemStack>>() {})
        .id("inventory_id")
        .name("Inventory ID")
        .query(DataQuery.of('.', "inventory_id.name"))
        .build();
GameRegistryEvent.Register<Key<?>>

@Listener
public void GameRegistryEventRegisterKey(GameRegistryEvent.Register<Key<?>> event) {
event.register(ToolKeys.INVENTORY);
}

DataRegistration

@Listener
public void GamePreInitialization(GamePreInitializationEvent event) throws IOException {
DataRegistration.builder()
.name(“My Inventory Data”)
.id(“inventory_data”) // prefix is added for you and you can’t add it yourself
.dataClass(MyInventoryData.class)
.immutableClass(MyImmutableInventoryData.class)
.builder(new MyInventoryDataBuilder()).build();
}

MyImmutableInventoryData

public class MyImmutableInventoryData extends AbstractImmutableData<MyImmutableInventoryData, MyInventoryData> {
private Map<Integer, ItemStack> inventory;

    public MyImmutableInventoryData(Map<Integer, ItemStack> inventory) {
        this.inventory = inventory;
        registerGetters();
    }

    @Override
    protected void registerGetters() {
        registerFieldGetter(ToolKeys.INVENTORY, () -> this.inventory);
        registerKeyValue(ToolKeys.INVENTORY, this::inventory);
    }

    public ImmutableMapValue<Integer, ItemStack> inventory() {
        return Sponge.getRegistry().getValueFactory().createMapValue(ToolKeys.INVENTORY, inventory).asImmutable();
    }

    @Override
    public MyInventoryData asMutable() {
        return new MyInventoryData(inventory);
    }

    @Override
    public int getContentVersion() {
        return 1;
    }

    @Override
    public DataContainer toContainer() {
        return super.toContainer()
                .set(ToolKeys.INVENTORY.getQuery(), this.inventory);
    }
}
MyInventoryData
public class MyInventoryData extends AbstractData<MyInventoryData, MyImmutableInventoryData> {
    private Map<Integer, ItemStack> inventory;


    public MyInventoryData(Map<Integer, ItemStack> inventory) {
        this.inventory = inventory;

        // you must call this!
        registerGettersAndSetters();
    }

    @Override
    protected void registerGettersAndSetters() {
        registerFieldGetter(ToolKeys.INVENTORY, () -> this.inventory);
        registerFieldSetter(ToolKeys.INVENTORY, inventory -> this.inventory = inventory);
        registerKeyValue(ToolKeys.INVENTORY, this::inventory);
    }

    public MapValue<Integer, ItemStack> inventory() {
        return Sponge.getRegistry().getValueFactory().createMapValue(ToolKeys.INVENTORY, inventory);
    }

    @Override
    public Optional<MyInventoryData> fill(DataHolder dataHolder, MergeFunction overlap) {
        Optional<MyInventoryData> otherData_ = dataHolder.get(MyInventoryData.class);
        if (otherData_.isPresent()) {
            MyInventoryData otherData = otherData_.get();
            MyInventoryData finalData = overlap.merge(this, otherData);
            this.inventory = finalData.inventory;
        }
        return Optional.of(this);
    }

    // the double method isn't strictly necessary but makes implementing the builder easier
    @Override
    public Optional<MyInventoryData> from(DataContainer container) {
        return from((DataView) container);
    }

    public Optional<MyInventoryData> from(DataView view) {
        if (view.contains(ToolKeys.INVENTORY.getQuery())) {
//            Optional<DataSerializable> v = view.getSerializable(ToolKeys.INVENTORY.getQuery(), DataSerializable.class);
//            DataSerializable v2 = v.get();

            this.inventory = (Map<Integer, ItemStack>) view.getMap(ToolKeys.INVENTORY.getQuery()).get();
//            this.inventory = view.getObject(ToolKeys.INVENTORY.getQuery(), HashMap.class).get();
            return Optional.of(this);
        } else {
            return Optional.empty();
        }
    }

    @Override
    public MyInventoryData copy() {
        return new MyInventoryData(this.inventory);
    }

    @Override
    public MyImmutableInventoryData asImmutable() {
        return new MyImmutableInventoryData(this.inventory);
    }

    @Override
    public int getContentVersion() {
        return 1;
    }

    // IMPORTANT this is what causes your data to be written to NBT
    @Override
    public DataContainer toContainer() {
        return super.toContainer()
                .set(ToolKeys.INVENTORY.getQuery(), this.inventory);
    }
}
MyInventoryDataBuilder
public class MyInventoryDataBuilder extends AbstractDataBuilder<MyInventoryData> implements DataManipulatorBuilder<MyInventoryData, MyImmutableInventoryData> {
    public MyInventoryDataBuilder() {
        super(MyInventoryData.class, 1);
    }

    @Override
    public MyInventoryData create() {
        HashMap<Integer, ItemStack> inventory = new HashMap<Integer, ItemStack>();
        return new MyInventoryData(inventory);
    }

    @Override
    public Optional<MyInventoryData> createFrom(DataHolder dataHolder) {
        return create().fill(dataHolder);
    }

    @Override
    protected Optional<MyInventoryData> buildContent(DataView container) throws InvalidDataException {
        return create().from(container);
    }
}

#9

Map extraction does not work well. You cannot simply cast it. I recommend not using getMap, instead doing it yourself with getKeys(false)/getView.


#10

Je peux a voir un exemple ? Merci

[ translate.google.fr ]
Can I see an example? Thank you


#11
DataView invView = view.getView(ToolKeys.INVENTORY.getQuery());
Map<Integer, ItemStack> map = new HashMap<>();
for (DataQuery query : invView.getKeys(false)) {
    ItemStack stack = invView.getSerializable(query, ItemStack.class).get();
    int key = Integer.parseInt(query.toString());
    map.put(key, stack);
}
this.inventory = map;

#12

I have a new problem:

java.lang.IllegalArgumentException: Unable to translate object to NBTBase: Z

this.axis = view.getObject(ToolKeys.AXIS.getQuery(), Axis.class).get();

    AXIS = Key.builder()
            .type(TypeTokens.AXIS_VALUE_TOKEN)
            .id("axis_id")
            .name("Axis ID")
            .query(DataQuery.of('.', "axis"))
            .build();

edit:
solved:
.set(ToolKeys.AXIS.getQuery(), this.axis.name())

this.axis = Axis.valueOf(view.getString(ToolKeys.AXIS.getQuery()).get());