package com.seodisparate.TurnBasedMinecraft;
+import java.time.Duration;
+
import org.apache.logging.log4j.Logger;
+import com.seodisparate.TurnBasedMinecraft.common.Battle;
import com.seodisparate.TurnBasedMinecraft.common.BattleManager;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleDecision;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleEntered;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleExited;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleInfo;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleRequestInfo;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketHandler;
import net.minecraft.entity.Entity;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import net.minecraftforge.fml.relauncher.Side;
@Mod(modid = TurnBasedMinecraftMod.MODID, name = TurnBasedMinecraftMod.NAME, version = TurnBasedMinecraftMod.VERSION)
public class TurnBasedMinecraftMod
public static final String MODID = "com.seodisparate.turnbasedminecraft";
public static final String NAME = "Turn Based Minecraft Mod";
public static final String VERSION = "1.0";
+ public static final Duration BattleDecisionTime = Duration.ofSeconds(15);
private static Logger logger;
- private static BattleManager battleManager;
-
+ public static BattleManager battleManager;
+ private static int packetHandlerID = 0;
public static Entity attackingEntity;
+
+ public static Battle currentBattle;
@EventHandler
public void preInit(FMLPreInitializationEvent event)
@EventHandler
public void init(FMLInitializationEvent event)
{
- battleManager = new BattleManager();
+ currentBattle = null;
+ if(event.getSide() == Side.SERVER)
+ {
+ battleManager = new BattleManager();
+ }
+ else
+ {
+ battleManager = null;
+ }
+
+ // register packets
+ PacketHandler.INSTANCE.registerMessage(
+ PacketBattleEntered.HandlerBattleEntered.class,
+ PacketBattleEntered.class,
+ packetHandlerID++,
+ Side.CLIENT);
+ PacketHandler.INSTANCE.registerMessage(
+ PacketBattleExited.HandlerBattleExited.class,
+ PacketBattleExited.class,
+ packetHandlerID++,
+ Side.CLIENT);
+ PacketHandler.INSTANCE.registerMessage(
+ PacketBattleInfo.HandlerBattleInfo.class,
+ PacketBattleInfo.class,
+ packetHandlerID++,
+ Side.CLIENT);
+ PacketHandler.INSTANCE.registerMessage(
+ PacketBattleRequestInfo.HandlerBattleRequestInfo.class,
+ PacketBattleRequestInfo.class,
+ packetHandlerID++,
+ Side.SERVER);
+ PacketHandler.INSTANCE.registerMessage(
+ PacketBattleDecision.HandleBattleDecision.class,
+ PacketBattleDecision.class,
+ packetHandlerID++,
+ Side.SERVER);
}
+
+ /*
+ @EventHandler
+ public void postInit(FMLPostInitializationEvent event)
+ {
+ }
+ */
@EventHandler
public void entityAttacked(LivingAttackEvent event)
{
- if(!event.getEntity().equals(attackingEntity) && battleManager.checkAttack(event))
+ if(battleManager == null)
+ {
+ return;
+ }
+ if(!event.getSource().getTrueSource().equals(attackingEntity) && battleManager.checkAttack(event))
{
logger.debug("Canceled LivingAttackEvent between " + attackingEntity + " and " + event.getEntity());
event.setCanceled(true);
import java.time.Duration;
import java.time.Instant;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+
import net.minecraft.entity.Entity;
+import net.minecraft.entity.player.EntityPlayer;
public class Battle
{
- private int id;
- private Map<Integer, Entity> sideA;
- private Map<Integer, Entity> sideB;
+ private final int id;
+ private Map<Integer, Combatant> sideA;
+ private Map<Integer, Combatant> sideB;
private Instant lastUpdated;
+ private State state;
+ private int playerCount;
+ private int undecidedCount;
+ private Duration timer;
+
+ public enum State
+ {
+ DECISION,
+ ATTACK,
+ HEALTH_CHECK
+ }
+
+ public enum Decision
+ {
+ UNDECIDED(0),
+ ATTACK(1),
+ DEFEND(2),
+ FLEE(3),
+ USE_ITEM(4);
+
+ private int value;
+ private static Map<Integer, Decision> map = new HashMap<Integer, Decision>();
+
+ private Decision(int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ static
+ {
+ for(Decision decision : Decision.values())
+ {
+ map.put(decision.value, decision);
+ }
+ }
+
+ public static Decision valueOf(int decisionType)
+ {
+ return map.get(decisionType);
+ }
+ }
public Battle(int id, Collection<Entity> sideA, Collection<Entity> sideB)
{
this.id = id;
- this.sideA = new Hashtable<Integer, Entity>();
- this.sideB = new Hashtable<Integer, Entity>();
- for(Entity e : sideA)
+ this.sideA = new Hashtable<Integer, Combatant>();
+ this.sideB = new Hashtable<Integer, Combatant>();
+ playerCount = 0;
+ if(sideA != null)
{
- this.sideA.put(e.getEntityId(), e);
+ for(Entity e : sideA)
+ {
+ this.sideA.put(e.getEntityId(), new Combatant(e));
+ if(e instanceof EntityPlayer)
+ {
+ ++playerCount;
+ }
+ }
}
- for(Entity e : sideB)
+ if(sideB != null)
{
- this.sideB.put(e.getEntityId(), e);
+ for(Entity e : sideB)
+ {
+ this.sideB.put(e.getEntityId(), new Combatant(e));
+ if(e instanceof EntityPlayer)
+ {
+ ++playerCount;
+ }
+ }
}
lastUpdated = null;
+ state = State.DECISION;
+ undecidedCount = playerCount;
+ timer = TurnBasedMinecraftMod.BattleDecisionTime;
}
public int getId()
public void addCombatantToSideA(Entity e)
{
- sideA.put(e.getEntityId(), e);
+ sideA.put(e.getEntityId(), new Combatant(e));
+ if(e instanceof EntityPlayer)
+ {
+ ++playerCount;
+ if(state == State.DECISION)
+ {
+ ++undecidedCount;
+ }
+ }
}
public void addCombatantToSideB(Entity e)
{
- sideB.put(e.getEntityId(), e);
+ sideB.put(e.getEntityId(), new Combatant(e));
+ if(e instanceof EntityPlayer)
+ {
+ ++playerCount;
+ if(state == State.DECISION)
+ {
+ ++undecidedCount;
+ }
+ }
+ }
+
+ public void clearCombatants()
+ {
+ sideA.clear();
+ sideB.clear();
+ playerCount = 0;
+ undecidedCount = 0;
+ }
+
+ public Collection<Combatant> getSideA()
+ {
+ return sideA.values();
+ }
+
+ public Collection<Combatant> getSideB()
+ {
+ return sideB.values();
+ }
+
+ public Collection<Integer> getSideAIDs()
+ {
+ Collection<Integer> sideAIDs = new ArrayList<Integer>(sideA.size());
+ for(Combatant combatant : sideA.values())
+ {
+ sideAIDs.add(combatant.entity.getEntityId());
+ }
+ return sideAIDs;
+ }
+
+ public Collection<Integer> getSideBIDs()
+ {
+ Collection<Integer> sideBIDs = new ArrayList<Integer>(sideB.size());
+ for(Combatant combatant : sideB.values())
+ {
+ sideBIDs.add(combatant.entity.getEntityId());
+ }
+ return sideBIDs;
+ }
+
+ public Combatant getCombatantByID(int entityID)
+ {
+ Combatant combatant = sideA.get(entityID);
+ if(combatant == null)
+ {
+ combatant = sideB.get(entityID);
+ }
+ return combatant;
+ }
+
+ public void setDecision(int entityID, Decision decision)
+ {
+ if(state != State.DECISION)
+ {
+ return;
+ }
+ Combatant combatant = sideA.get(entityID);
+ if(combatant == null)
+ {
+ combatant = sideB.get(entityID);
+ if(combatant == null)
+ {
+ return;
+ }
+ }
+
+ if(combatant.entity instanceof EntityPlayer)
+ {
+ combatant.decision = decision;
+ --undecidedCount;
+ }
+ }
+
+ public State getState()
+ {
+ return state;
}
public void update()
}
}
- private void update(Duration dt)
+ private void update(final Duration dt)
{
+ switch(state)
+ {
+ case DECISION:
+ timer = timer.minus(dt);
+ if(timer.isNegative() || timer.isZero())
+ {
+ state = State.ATTACK;
+ timer = TurnBasedMinecraftMod.BattleDecisionTime;
+ update(Duration.ZERO);
+ }
+ break;
+ case ATTACK:
+ // TODO
+ break;
+ case HEALTH_CHECK:
+ // TODO
+ break;
+ }
}
}
import java.util.Hashtable;
import java.util.Map;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketBattleEntered;
+import com.seodisparate.TurnBasedMinecraft.common.networking.PacketHandler;
+
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
+import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
public class BattleManager
Entity inBattle = null;
Entity notInBattle = null;
Battle battle = null;
+
for(Battle b : battleMap.values())
{
if(b.hasCombatant(event.getSource().getTrueSource().getEntityId()))
{
- inBattle = event.getSource().getTrueSource();
- battle = b;
- break;
+ if(inBattle != null)
+ {
+ // both combatants are in battle
+ return true;
+ }
+ else
+ {
+ inBattle = event.getSource().getTrueSource();
+ notInBattle = event.getEntity();
+ battle = b;
+ }
}
- }
- if(inBattle != null)
- {
- notInBattle = event.getEntity();
- } else
- {
- notInBattle = event.getSource().getTrueSource();
- }
- for(Battle b : battleMap.values())
- {
if(b.hasCombatant(event.getEntity().getEntityId()))
{
if(inBattle != null)
{
- // both combatants in battle
+ // both combatants are in battle
return true;
}
- inBattle = event.getEntity();
- battle = b;
- break;
+ else
+ {
+ inBattle = event.getEntity();
+ notInBattle = event.getSource().getTrueSource();
+ battle = b;
+ }
}
}
+
if(inBattle == null)
{
// neither entity is in battle
{
battle.addCombatantToSideA(notInBattle);
}
+
+ if(notInBattle instanceof EntityPlayerMP)
+ {
+ PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)notInBattle);
+ }
return true;
}
}
Battle newBattle = new Battle(IDCounter, sideA, sideB);
battleMap.put(IDCounter, newBattle);
+ for(Entity e : sideA)
+ {
+ if(e instanceof EntityPlayerMP)
+ {
+ PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)e);
+ }
+ }
+ for(Entity e : sideB)
+ {
+ if(e instanceof EntityPlayerMP)
+ {
+ PacketHandler.INSTANCE.sendTo(new PacketBattleEntered(IDCounter), (EntityPlayerMP)e);
+ }
+ }
return newBattle;
}
-}
+
+ public Battle getBattleByID(int id)
+ {
+ return battleMap.get(id);
+ }
+}
\ No newline at end of file
public class BattleUpdater implements Runnable
{
- BattleManager manager;
+ private BattleManager manager;
+ private boolean isRunning;
public BattleUpdater(BattleManager manager)
{
this.manager = manager;
+ isRunning = true;
}
@Override
public void run()
{
- for(Battle e : manager.battleMap.values())
+ while(isRunning)
{
- e.update();
+ for(Battle e : manager.battleMap.values())
+ {
+ e.update();
+ }
+ try { Thread.sleep(250); } catch (Exception e) { /* ignored */ }
}
- try { Thread.sleep(250); } catch (Exception e) { /* ignored */ }
+ }
+
+ public void setIsRunning(boolean isRunning)
+ {
+ this.isRunning = isRunning;
}
}
\ No newline at end of file
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common;
+
+import net.minecraft.entity.Entity;
+
+public class Combatant
+{
+ public Entity entity;
+ public Battle.Decision decision;
+ public int itemToUse;
+ public float speed;
+
+ public Combatant()
+ {
+ decision = Battle.Decision.UNDECIDED;
+ speed = 0.5f;
+ }
+
+ public Combatant(Entity e)
+ {
+ entity = e;
+ decision = Battle.Decision.UNDECIDED;
+ speed = 0.5f;
+ }
+
+ public Combatant(Entity e, float speed)
+ {
+ entity = e;
+ decision = Battle.Decision.UNDECIDED;
+ this.speed = speed;
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+import com.seodisparate.TurnBasedMinecraft.common.Battle;
+import com.seodisparate.TurnBasedMinecraft.common.Battle.Decision;
+import com.seodisparate.TurnBasedMinecraft.common.Combatant;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraft.entity.player.EntityPlayerMP;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleDecision implements IMessage
+{
+ private int battleID;
+ private Battle.Decision decision;
+
+ public PacketBattleDecision() {}
+
+ public PacketBattleDecision(int battleID, Battle.Decision decision)
+ {
+ this.battleID = battleID;
+ this.decision = decision;
+ }
+
+ @Override
+ public void fromBytes(ByteBuf buf)
+ {
+ battleID = buf.readInt();
+ decision = Decision.valueOf(buf.readInt());
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf)
+ {
+ buf.writeInt(battleID);
+ buf.writeInt(decision.getValue());
+ }
+
+ public static class HandleBattleDecision implements IMessageHandler<PacketBattleDecision, IMessage>
+ {
+ @Override
+ public IMessage onMessage(PacketBattleDecision message, MessageContext ctx)
+ {
+ Battle b = TurnBasedMinecraftMod.battleManager.getBattleByID(message.battleID);
+ if(b != null && b.getState() == Battle.State.DECISION)
+ {
+ EntityPlayerMP player = ctx.getServerHandler().player;
+ b.setDecision(player.getEntityId(), message.decision);
+ }
+ return null;
+ }
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+import com.seodisparate.TurnBasedMinecraft.common.Battle;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleEntered implements IMessage
+{
+ private int battleID;
+
+ public PacketBattleEntered() {}
+
+ public PacketBattleEntered(int battleID)
+ {
+ this.battleID = battleID;
+ }
+
+ @Override
+ public void fromBytes(ByteBuf buf)
+ {
+ battleID = buf.readInt();
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf)
+ {
+ buf.writeInt(battleID);
+ }
+
+ public static class HandlerBattleEntered implements IMessageHandler<PacketBattleEntered, PacketBattleRequestInfo>
+ {
+ @Override
+ public PacketBattleRequestInfo onMessage(PacketBattleEntered message, MessageContext ctx)
+ {
+ TurnBasedMinecraftMod.currentBattle = new Battle(message.battleID, null, null);
+ return new PacketBattleRequestInfo(message.battleID);
+ }
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleExited implements IMessage
+{
+ @Override
+ public void fromBytes(ByteBuf buf)
+ {
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf)
+ {
+ }
+
+ public static class HandlerBattleExited implements IMessageHandler<PacketBattleExited, IMessage>
+ {
+ @Override
+ public IMessage onMessage(PacketBattleExited message, MessageContext ctx)
+ {
+ TurnBasedMinecraftMod.currentBattle = null;
+ return null;
+ }
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraft.client.Minecraft;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleInfo implements IMessage
+{
+ private Collection<Integer> sideA;
+ private Collection<Integer> sideB;
+
+ public PacketBattleInfo()
+ {
+ sideA = new ArrayList<Integer>();
+ sideB = new ArrayList<Integer>();
+ }
+
+ public PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> sideB)
+ {
+ this.sideA = sideA;
+ this.sideB = sideB;
+ }
+
+ @Override
+ public void fromBytes(ByteBuf buf)
+ {
+ int sideACount = buf.readInt();
+ int sideBCount = buf.readInt();
+ for(int i = 0; i < sideACount; ++i)
+ {
+ sideA.add(buf.readInt());
+ }
+ for(int i = 0; i < sideBCount; ++i)
+ {
+ sideB.add(buf.readInt());
+ }
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf)
+ {
+ buf.writeInt(sideA.size());
+ buf.writeInt(sideB.size());
+ for(Integer id : sideA)
+ {
+ buf.writeInt(id);
+ }
+ for(Integer id : sideB)
+ {
+ buf.writeInt(id);
+ }
+ }
+
+ public static class HandlerBattleInfo implements IMessageHandler<PacketBattleInfo, IMessage>
+ {
+ @Override
+ public IMessage onMessage(PacketBattleInfo message, MessageContext ctx)
+ {
+ if(TurnBasedMinecraftMod.currentBattle == null)
+ {
+ return null;
+ }
+ TurnBasedMinecraftMod.currentBattle.clearCombatants();
+ for(Integer id : message.sideA)
+ {
+ TurnBasedMinecraftMod.currentBattle.addCombatantToSideA(Minecraft.getMinecraft().world.getEntityByID(id));
+ }
+ for(Integer id : message.sideB)
+ {
+ TurnBasedMinecraftMod.currentBattle.addCombatantToSideB(Minecraft.getMinecraft().world.getEntityByID(id));
+ }
+ return null;
+ }
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+import com.seodisparate.TurnBasedMinecraft.common.Battle;
+
+import io.netty.buffer.ByteBuf;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
+import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
+import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
+
+public class PacketBattleRequestInfo implements IMessage
+{
+ private int battleID;
+
+ public PacketBattleRequestInfo() {}
+
+ public PacketBattleRequestInfo(int battleID)
+ {
+ this.battleID = battleID;
+ }
+
+ @Override
+ public void fromBytes(ByteBuf buf)
+ {
+ battleID = buf.readInt();
+ }
+
+ @Override
+ public void toBytes(ByteBuf buf)
+ {
+ buf.writeInt(battleID);
+ }
+
+ public static class HandlerBattleRequestInfo implements IMessageHandler<PacketBattleRequestInfo, PacketBattleInfo>
+ {
+ @Override
+ public PacketBattleInfo onMessage(PacketBattleRequestInfo message, MessageContext ctx)
+ {
+ Battle b = TurnBasedMinecraftMod.battleManager.getBattleByID(message.battleID);
+ if(b == null)
+ {
+ return null;
+ }
+ PacketBattleInfo battleInfo = new PacketBattleInfo(b.getSideAIDs(), b.getSideBIDs());
+ return battleInfo;
+ }
+ }
+}
--- /dev/null
+package com.seodisparate.TurnBasedMinecraft.common.networking;
+
+import com.seodisparate.TurnBasedMinecraft.TurnBasedMinecraftMod;
+
+import net.minecraftforge.fml.common.network.NetworkRegistry;
+import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
+
+public class PacketHandler
+{
+ public static final SimpleNetworkWrapper INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(TurnBasedMinecraftMod.MODID);
+}