WIP backend logic impl, fixes to config gen/parse

This commit is contained in:
Stephen Seo 2018-09-07 16:41:22 +09:00
parent 0520e163f8
commit 97cfdaf0f7
5 changed files with 533 additions and 354 deletions

View file

@ -20,6 +20,7 @@ import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
@Mod(modid = TurnBasedMinecraftMod.MODID, name = TurnBasedMinecraftMod.NAME, version = TurnBasedMinecraftMod.VERSION)
@ -32,7 +33,8 @@ public class TurnBasedMinecraftMod
public static final String CONFIG_FILENAME = "TBM_Config.xml";
public static final String CONFIG_DIRECTORY = "config/TurnBasedMinecraft/";
public static final String CONFIG_FILE_PATH = CONFIG_DIRECTORY + CONFIG_FILENAME;
public static final int CONFIG_FILE_VERSION = 1; // TODO derive this from internal config
public static final String CONFIG_INTERNAL_PATH = "/assets/TurnBasedMinecraft/" + CONFIG_FILENAME;
private static int CONFIG_FILE_VERSION = 0;
private static Logger logger;
private static BattleManager battleManager;
@ -47,6 +49,7 @@ public class TurnBasedMinecraftMod
public void preInit(FMLPreInitializationEvent event)
{
logger = event.getModLog();
logger.debug("PREINIT");
}
@EventHandler
@ -83,6 +86,7 @@ public class TurnBasedMinecraftMod
PacketBattleMessage.class,
packetHandlerID++,
Side.CLIENT);
logger.debug("INIT");
}
@EventHandler
@ -92,9 +96,10 @@ public class TurnBasedMinecraftMod
{
config = new Config(logger);
}
logger.debug("POSTINIT");
}
@EventHandler
@SubscribeEvent
public void entityAttacked(LivingAttackEvent event)
{
if(battleManager == null)
@ -113,4 +118,14 @@ public class TurnBasedMinecraftMod
{
return battleManager;
}
public static void setConfigVersion(int version)
{
CONFIG_FILE_VERSION = version;
}
public static int getConfigVersion()
{
return CONFIG_FILE_VERSION;
}
}

View file

@ -21,6 +21,13 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemLingeringPotion;
import net.minecraft.item.ItemPotion;
import net.minecraft.item.ItemSplashPotion;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
public class Battle
@ -43,8 +50,7 @@ public class Battle
public enum State
{
DECISION,
ACTION,
HEALTH_CHECK
ACTION
}
public enum Decision
@ -357,6 +363,76 @@ public class Battle
}
}
private void sendMessageToAllPlayers(PacketBattleMessage.MessageType type, int from, int to, int amount, String custom)
{
if(!isServer)
{
return;
}
for(Combatant p : players.values())
{
if(p.entity.isEntityAlive())
{
PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(type, from, to, amount, custom), (EntityPlayerMP)p.entity);
}
}
}
/**
* @return true if at least one combatant was removed
*/
private boolean healthCheck()
{
Queue<Integer> removeQueue = new ArrayDeque<Integer>();
for(Combatant c : sideA.values())
{
if(!c.entity.isEntityAlive())
{
removeQueue.add(c.entity.getEntityId());
if(c.entity instanceof EntityPlayer)
{
PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
}
sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
}
}
for(Combatant c : sideB.values())
{
if(!c.entity.isEntityAlive())
{
removeQueue.add(c.entity.getEntityId());
if(c.entity instanceof EntityPlayer)
{
PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
}
sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
}
}
boolean didRemove = !removeQueue.isEmpty();
Integer toRemove = removeQueue.poll();
while(toRemove != null)
{
sideA.remove(toRemove);
sideB.remove(toRemove);
if(players.remove(toRemove) != null)
{
playerCount.decrementAndGet();
}
toRemove = removeQueue.poll();
}
if(players.isEmpty() || sideA.isEmpty() || sideB.isEmpty())
{
battleEnded = true;
sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENDED, 0, 0, 0);
}
else if(didRemove)
{
notifyPlayersBattleInfo();
}
return didRemove;
}
private boolean update(final Duration dt)
{
if(battleEnded)
@ -421,6 +497,10 @@ public class Battle
}
update(Duration.ZERO);
}
else
{
healthCheck();
}
break;
case ACTION:
{
@ -436,8 +516,7 @@ public class Battle
{
case UNDECIDED:
sendMessageToAllPlayers(PacketBattleMessage.MessageType.DID_NOTHING, next.entity.getEntityId(), 0, 0);
next = turnOrderQueue.poll();
continue;
break;
case ATTACK:
Combatant target = null;
if(next.entity instanceof EntityPlayer)
@ -452,8 +531,7 @@ public class Battle
}
if(target == null || !target.entity.isEntityAlive())
{
next = turnOrderQueue.poll();
continue;
break;
}
int hitChance = TurnBasedMinecraftMod.config.getPlayerAttackProbability();
if(target.entity instanceof EntityPlayer)
@ -677,6 +755,28 @@ public class Battle
}
break;
case USE_ITEM:
ItemStack targetItemStack = ((EntityPlayer)next.entity).inventory.getStackInSlot(next.itemToUse);
Item targetItem = targetItemStack.getItem();
if(targetItem == null)
{
sendMessageToAllPlayers(PacketBattleMessage.MessageType.USED_ITEM, next.entity.getEntityId(), 0, PacketBattleMessage.UsedItemAction.USED_NOTHING.getValue());
break;
}
if(targetItem instanceof ItemFood)
{
sendMessageToAllPlayers(PacketBattleMessage.MessageType.USED_ITEM, next.entity.getEntityId(), 0, PacketBattleMessage.UsedItemAction.USED_FOOD.getValue(), targetItemStack.getDisplayName());
((ItemFood)targetItem).onItemUseFinish(targetItemStack, next.entity.world, (EntityLivingBase)next.entity);
}
else if(targetItem instanceof ItemPotion && !(targetItem instanceof ItemSplashPotion) && !(targetItem instanceof ItemLingeringPotion))
{
sendMessageToAllPlayers(PacketBattleMessage.MessageType.USED_ITEM, next.entity.getEntityId(), 0, PacketBattleMessage.UsedItemAction.USED_POTION.getValue(), targetItemStack.getDisplayName());
((ItemPotion)targetItem).onItemUseFinish(targetItemStack, next.entity.world, (EntityLivingBase)next.entity);
((EntityPlayer)next.entity).inventory.setInventorySlotContents(next.itemToUse, new ItemStack(Items.GLASS_BOTTLE));
}
else
{
sendMessageToAllPlayers(PacketBattleMessage.MessageType.USED_ITEM, next.entity.getEntityId(), 0, PacketBattleMessage.UsedItemAction.USED_INVALID.getValue(), targetItemStack.getDisplayName());
}
break;
}
next = turnOrderQueue.poll();
@ -689,62 +789,11 @@ public class Battle
{
c.decision = Decision.UNDECIDED;
}
state = State.HEALTH_CHECK;
update(Duration.ZERO);
break;
}
case HEALTH_CHECK:
Queue<Integer> removeQueue = new ArrayDeque<Integer>();
for(Combatant c : sideA.values())
{
if(!c.entity.isEntityAlive())
{
removeQueue.add(c.entity.getEntityId());
if(c.entity instanceof EntityPlayer)
{
PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
}
sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
}
}
for(Combatant c : sideB.values())
{
if(!c.entity.isEntityAlive())
{
removeQueue.add(c.entity.getEntityId());
if(c.entity instanceof EntityPlayer)
{
PacketHandler.INSTANCE.sendTo(new PacketBattleMessage(PacketBattleMessage.MessageType.ENDED, c.entity.getEntityId(), 0, 0), (EntityPlayerMP)c.entity);
}
sendMessageToAllPlayers(PacketBattleMessage.MessageType.DIED, c.entity.getEntityId(), 0, 0);
}
}
boolean didRemove = !removeQueue.isEmpty();
Integer toRemove = removeQueue.poll();
while(toRemove != null)
{
sideA.remove(toRemove);
sideB.remove(toRemove);
if(players.remove(toRemove) != null)
{
playerCount.decrementAndGet();
}
toRemove = removeQueue.poll();
}
if(players.isEmpty() || sideA.isEmpty() || sideB.isEmpty())
{
battleEnded = true;
sendMessageToAllPlayers(PacketBattleMessage.MessageType.ENDED, 0, 0, 0);
}
else if(didRemove)
{
notifyPlayersBattleInfo();
}
state = State.DECISION;
undecidedCount.set(playerCount.get());
timer = TurnBasedMinecraftMod.BattleDecisionTime;
healthCheck();
break;
}
} // case ACTION
} // switch(state)
return battleEnded;
}
} // update(final Duration dt)
}

View file

@ -2,10 +2,11 @@ package com.seodisparate.TurnBasedMinecraft.common;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.HashSet;
@ -36,18 +37,32 @@ public class Config
private int fleeGoodProbability = 90;
private int fleeBadProbability = 40;
private enum ConfigParseResult
{
IS_OLD,
SUCCESS
}
public Config(Logger logger)
{
entityInfoMap = new HashMap<String, EntityInfo>();
ignoreBattleTypes = new HashSet<EntityInfo.Category>();
this.logger = logger;
int internalVersion = 0;
try
{
InputStream is = getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_INTERNAL_PATH);
if(is == null)
{
logger.error("Internal resource is null");
}
internalVersion = getConfigFileVersion(is);
} catch (Exception e) {}
if(internalVersion == 0)
{
logger.error("Failed to check version of internal config file");
}
else
{
TurnBasedMinecraftMod.setConfigVersion(internalVersion);
}
try
{
File testLoad = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
@ -68,27 +83,26 @@ public class Config
logger.error("Failed to read/parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
return;
}
try
{
ConfigParseResult result = parseConfig(configFile);
if(result == ConfigParseResult.IS_OLD)
int configVersion = getConfigFileVersion(configFile);
if(configVersion < TurnBasedMinecraftMod.getConfigVersion())
{
logger.warn("Config file " + TurnBasedMinecraftMod.CONFIG_FILENAME + " is older version, renaming...");
moveOldConfig();
try
{
writeConfig();
ConfigParseResult resultSecond = parseConfig(configFile);
if(resultSecond != ConfigParseResult.SUCCESS)
{
logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
}
}
else if(result != ConfigParseResult.SUCCESS)
{
logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
}
} catch (Exception e)
{
logger.error("Failed to parse config file " + TurnBasedMinecraftMod.CONFIG_FILE_PATH);
logger.error("Failed to write config file!");
}
}
try
{
parseConfig(configFile);
} catch (Exception e)
{
logger.error("Failed to parse config file!");
}
}
@ -97,7 +111,7 @@ public class Config
File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
File dirs = configFile.getParentFile();
dirs.mkdirs();
InputStream configStream = this.getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_FILENAME);
InputStream configStream = this.getClass().getResourceAsStream(TurnBasedMinecraftMod.CONFIG_INTERNAL_PATH);
FileOutputStream configOutput = new FileOutputStream(configFile);
byte[] buf = new byte[4096];
int read = 0;
@ -120,12 +134,12 @@ public class Config
{
configFile.renameTo(new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY
+ "TBM_Config_"
+ DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(Instant.now())
+ DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now())
+ ".xml"));
}
}
private ConfigParseResult parseConfig(File configFile) throws XMLStreamException, FactoryConfigurationError, IOException
private boolean parseConfig(File configFile) throws XMLStreamException, FactoryConfigurationError, IOException
{
FileInputStream fis = new FileInputStream(configFile);
XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(fis);
@ -140,13 +154,6 @@ public class Config
}
else if(xmlReader.getLocalName().equals("Version"))
{
if(Integer.parseInt(xmlReader.getElementText()) < TurnBasedMinecraftMod.CONFIG_FILE_VERSION)
{
logger.info("Config file is older version, moving it and writing a new one in its place");
xmlReader.close();
fis.close();
return ConfigParseResult.IS_OLD;
}
continue;
}
else if(xmlReader.getLocalName().equals("IgnoreBattleTypes"))
@ -217,7 +224,6 @@ public class Config
} catch (ClassNotFoundException e)
{
logger.error("Failed to get class of name " + classType);
continue;
}
do
{
@ -322,15 +328,18 @@ public class Config
}
}
} while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals(classType)));
if(eInfo.classType != null)
{
entityInfoMap.put(eInfo.classType.getName(), eInfo);
}
}
} while(!(xmlReader.isEndElement() && xmlReader.getLocalName().equals("EntityStats")));
}
}
}
xmlReader.close();
fis.close();
return ConfigParseResult.SUCCESS;
return true;
}
public int getPlayerSpeed()
@ -408,4 +417,40 @@ public class Config
}
return null;
}
private int getConfigFileVersion(File configFile)
{
try
{
return getConfigFileVersion(new FileInputStream(configFile));
} catch(FileNotFoundException e)
{
return 0;
}
}
private int getConfigFileVersion(InputStream configStream)
{
int configVersion = 1;
try
{
XMLStreamReader xmlReader = XMLInputFactory.newInstance().createXMLStreamReader(configStream);
while(xmlReader.hasNext())
{
xmlReader.next();
if(xmlReader.isStartElement() && xmlReader.getLocalName().equals("Version"))
{
configVersion = Integer.parseInt(xmlReader.getElementText());
break;
}
}
xmlReader.close();
} catch (Exception e)
{
return 0;
}
return configVersion;
}
}

View file

@ -13,6 +13,7 @@ import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.scoreboard.ScorePlayerTeam;
import net.minecraft.util.text.TextComponentString;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
@ -30,7 +31,8 @@ public class PacketBattleMessage implements IMessage
DEFENSE_DAMAGE(6),
MISS(7),
DEFENDING(8),
DID_NOTHING(9);
DID_NOTHING(9),
USED_ITEM(10);
private int value;
private static Map<Integer, MessageType> map = new HashMap<Integer, MessageType>();
@ -59,12 +61,47 @@ public class PacketBattleMessage implements IMessage
}
}
public enum UsedItemAction
{
USED_NOTHING(0),
USED_INVALID(1),
USED_FOOD(2),
USED_POTION(3);
private int value;
private static Map<Integer, UsedItemAction> map = new HashMap<Integer, UsedItemAction>();
private UsedItemAction(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
static
{
for(UsedItemAction type : UsedItemAction.values())
{
map.put(type.getValue(), type);
}
}
public static UsedItemAction valueOf(int value)
{
return map.get(value);
}
}
MessageType messageType;
int entityIDFrom;
int entityIDTo;
int amount;
String custom;
public PacketBattleMessage() {}
public PacketBattleMessage() { custom = new String(); }
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, int amount)
{
@ -72,6 +109,16 @@ public class PacketBattleMessage implements IMessage
this.entityIDFrom = entityIDFrom;
this.entityIDTo = entityIDTo;
this.amount = amount;
custom = new String();
}
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, int amount, String custom)
{
this.messageType = messageType;
this.entityIDFrom = entityIDFrom;
this.entityIDTo = entityIDTo;
this.amount = amount;
this.custom = custom;
}
@Override
@ -81,6 +128,7 @@ public class PacketBattleMessage implements IMessage
entityIDFrom = buf.readInt();
entityIDTo = buf.readInt();
amount = buf.readInt();
custom = ByteBufUtils.readUTF8String(buf);
}
@Override
@ -90,6 +138,7 @@ public class PacketBattleMessage implements IMessage
buf.writeInt(entityIDFrom);
buf.writeInt(entityIDTo);
buf.writeInt(amount);
ByteBufUtils.writeUTF8String(buf, custom);
}
public static class HandlerBattleMessage implements IMessageHandler<PacketBattleMessage, IMessage>
@ -226,6 +275,27 @@ public class PacketBattleMessage implements IMessage
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
from + " did nothing!"));
break;
case USED_ITEM:
switch(UsedItemAction.valueOf(message.amount))
{
case USED_NOTHING:
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
from + " tried to use nothing!"));
break;
case USED_INVALID:
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
from + " tried to consume " + message.custom + " and failed!"));
break;
case USED_FOOD:
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
from + " ate a " + message.custom + "!"));
break;
case USED_POTION:
Minecraft.getMinecraft().ingameGUI.getChatGUI().printChatMessage(new TextComponentString(
from + " drank a " + message.custom + "!"));
break;
}
break;
}
return null;
}

View file

@ -212,7 +212,7 @@
<Flee>0</Flee>
</Decision>
</net.minecraft.entity.monster.EntityShulker>
<net.minecraft.entity.monster.EntitySilverFish>
<net.minecraft.entity.monster.EntitySilverfish>
<AttackPower Probability="85">1</AttackPower>
<Evasion>37</Evasion>
<Category>monster</Category>
@ -222,7 +222,7 @@
<Defend>0</Defend>
<Flee>0</Flee>
</Decision>
</net.minecraft.entity.monster.EntitySilverFish>
</net.minecraft.entity.monster.EntitySilverfish>
<net.minecraft.entity.monster.EntitySkeleton>
<AttackPower Probability="75" Variance="1">3</AttackPower>
<Evasion>13</Evasion>