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

Implementation of behaviour structure, updated gradle version. #254

Open
wants to merge 2 commits into
base: 1.12.2
Choose a base branch
from
Open
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
3 changes: 1 addition & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#Mon Sep 14 12:28:28 PDT 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.8.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
3 changes: 3 additions & 0 deletions src/main/java/electroblob/wizardry/Wizardry.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import electroblob.wizardry.command.CommandViewAllies;
import electroblob.wizardry.data.DispenserCastingData;
import electroblob.wizardry.data.WizardData;
import electroblob.wizardry.entity.data.Behaviour;
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
import electroblob.wizardry.integration.baubles.WizardryBaublesIntegration;
import electroblob.wizardry.misc.Forfeit;
Expand Down Expand Up @@ -119,6 +120,8 @@ public void preInit(FMLPreInitializationEvent event){
WizardryBaublesIntegration.init();
WizardryAntiqueAtlasIntegration.init();

Behaviour.registerBehaviours();

}

@EventHandler
Expand Down
141 changes: 141 additions & 0 deletions src/main/java/electroblob/wizardry/entity/data/Behaviour.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package electroblob.wizardry.entity.data;

import electroblob.wizardry.Wizardry;
import net.minecraft.entity.Entity;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializer;
import net.minecraft.network.datasync.DataSerializers;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
* Describes a synced behavior. They follow the state design pattern, in that
* each behavior should be switchable over an entity, and is responsible for an
* update tick. Typically, behaviors are static inner classes, where the outer
* class extends Behavior and is the superclass of the inner classes.
* <p>
* All custom behaviors must be registered via {@link #registerBehaviour(Class)}.
* As Behaviors are most commonly synced with DataManager, a
* {@link BehaviorSerializer data serializer} is needed to synchronize server
* and client. It should be registered with
* {@link DataSerializers#registerSerializer(DataSerializer)}.
* <p>
* Make sure that subclasses receive the instance of entity.
*
* This class is generally used for creating multi-purpose entities,
* and reducing the amount of clutter and weird entity shenanigans you have going on.
* Spell specific behaviours should stay in their spell class, so as not to mess things up.
*
* @param E Type of entity this behavior is for
* @author FavouriteDragon, CrowsofWar, Aang23
*/
public abstract class Behaviour<E extends Entity> {

private static int nextId = 1;
private static Map<Integer, Class<? extends Behaviour>> behaviourIdToClass;
private static Map<Class<? extends Behaviour>, Integer> classToBehaviorId;

public Behaviour() {
}

// Static method called from preInit
public static void registerBehaviours() {

}

//Method used in abstract behaviour classes to register their own behaviours
protected static int registerBehaviour(Class<? extends Behaviour> behaviourClass) {
if (behaviourIdToClass == null) {
behaviourIdToClass = new HashMap<>();
classToBehaviorId = new HashMap<>();
nextId = 1;
}
int id = nextId++;
behaviourIdToClass.put(id, behaviourClass);
classToBehaviorId.put(behaviourClass, id);
return id;
}

/**
* Looks up the behavior class by the given Id, then instantiates an instance
* with reflection.
*/
public static Behaviour lookup(int id, Entity entity) {
try {

Behaviour behaviour = behaviourIdToClass.get(id).newInstance();
return behaviour;

} catch (Exception e) {

Wizardry.logger.error("Error constructing behavior...");
e.printStackTrace();
return null;

}
}

public int getId() {
return classToBehaviorId.get(getClass());
}

/**
* Called every update tick.
*
* @return Next Behavior. Return <code>this</code> to continue the Behavior.
* May never return null.
*/
public abstract Behaviour onUpdate(E entity);

public abstract void fromBytes(PacketBuffer buf);

public abstract void toBytes(PacketBuffer buf);

public abstract void load(NBTTagCompound nbt);

public abstract void save(NBTTagCompound nbt);

public static class BehaviorSerializer<B extends Behaviour<? extends Entity>> implements DataSerializer<B> {

// FIXME research- why doesn't read/write get called every time that
// behavior changes???

@Override
public void write(PacketBuffer buf, B value) {
buf.writeInt(value.getId());
value.toBytes(buf);
}

@Override
public B read(PacketBuffer buf) throws IOException {
try {

Behaviour behaviour = behaviourIdToClass.get(buf.readInt()).newInstance();
behaviour.fromBytes(buf);
return (B) behaviour;

} catch (Exception e) {

Wizardry.logger.error("Error reading Behavior from bytes");
e.printStackTrace();
return null;

}
}

@Override
public DataParameter<B> createKey(int id) {
return new DataParameter<>(id, this);
}

@Override
public B copyValue(B behaviour) {
return behaviour;
}

}
}