Some work on BattleManager and BattleUpdater

This commit is contained in:
Stephen Seo 2019-10-25 16:42:54 +09:00
parent b48406299a
commit f4b1bc9487
4 changed files with 91 additions and 112 deletions

View file

@ -6,13 +6,15 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.network.PacketDistributor;
import org.apache.logging.log4j.Logger;
import com.seodisparate.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
@ -20,19 +22,17 @@ public class BattleManager
{
private int IDCounter = 0;
protected Map<Integer, Battle> battleMap;
private Thread updaterThread;
private BattleUpdater battleUpdater;
private Logger logger;
private Map<Integer, Combatant> recentlyLeftBattle;
private BattleUpdater battleUpdater;
public BattleManager(Logger logger)
{
this.logger = logger;
battleMap = new HashMap<Integer, Battle>();
battleUpdater = new BattleUpdater(this);
updaterThread = new Thread(battleUpdater);
updaterThread.start();
recentlyLeftBattle = new HashMap<Integer, Combatant>();
battleUpdater = new BattleUpdater(this);
MinecraftForge.EVENT_BUS.register(battleUpdater);
}
/**
@ -47,14 +47,34 @@ public class BattleManager
{
Config config = TurnBasedMinecraftMod.proxy.getConfig();
// verify that both entities are EntityPlayer and not in creative or has a corresponding EntityInfo
if(!((event.getEntity() instanceof EntityPlayer && !((EntityPlayer)event.getEntity()).isCreative()) || (config.getEntityInfoReference(event.getEntity().getClass().getName()) != null || config.getCustomEntityInfoReference(event.getEntity().getCustomNameTag()) != null))
|| !((event.getSource().getTrueSource() instanceof EntityPlayer && !((EntityPlayer)event.getSource().getTrueSource()).isCreative()) || (config.getEntityInfoReference(event.getSource().getTrueSource().getClass().getName()) != null || config.getCustomEntityInfoReference(event.getSource().getTrueSource().getCustomNameTag()) != null)))
String receiverClassName = event.getEntity().getClass().getName();
String receiverCustomName;
try {
receiverCustomName = event.getEntity().getCustomName().getUnformattedComponentText();
} catch (NullPointerException e) {
receiverCustomName = null;
}
String attackerClassName;
try {
attackerClassName = event.getSource().getTrueSource().getClass().getName();
} catch (NullPointerException e) {
attackerClassName = null;
}
String attackerCustomName;
try {
attackerCustomName = event.getSource().getTrueSource().getCustomName().getUnformattedComponentText();
} catch (NullPointerException e) {
attackerCustomName = null;
}
if(!((event.getEntity() instanceof PlayerEntity && !((PlayerEntity)event.getEntity()).isCreative()) || (config.getEntityInfoReference(receiverClassName) != null || config.getCustomEntityInfoReference(receiverCustomName) != null))
|| !((event.getSource().getTrueSource() instanceof PlayerEntity && !((PlayerEntity)event.getSource().getTrueSource()).isCreative()) || (config.getEntityInfoReference(attackerClassName) != null || config.getCustomEntityInfoReference(attackerCustomName) != null)))
{
return false;
}
// check if ignore battle in config
EntityInfo entityInfo = config.getCustomEntityInfoReference(event.getEntity().getCustomNameTag());
EntityInfo entityInfo = config.getCustomEntityInfoReference(receiverCustomName);
if(entityInfo == null)
{
entityInfo = config.getMatchingEntityInfo(event.getEntity());
@ -78,7 +98,7 @@ public class BattleManager
return false;
}
entityInfo = config.getCustomEntityInfoReference(event.getSource().getTrueSource().getCustomNameTag());
entityInfo = config.getCustomEntityInfoReference(attackerCustomName);
if(entityInfo == null)
{
entityInfo = config.getMatchingEntityInfo(event.getSource().getTrueSource());
@ -147,7 +167,7 @@ public class BattleManager
if(inBattle == null)
{
// neither entity is in battle
if(event.getEntity() instanceof EntityPlayer || event.getSource().getTrueSource() instanceof EntityPlayer)
if(event.getEntity() instanceof PlayerEntity || event.getSource().getTrueSource() instanceof PlayerEntity)
{
// at least one of the entities is a player, create Battle
Collection<Entity> sideA = new ArrayList<Entity>(1);
@ -185,26 +205,39 @@ public class BattleManager
public void checkTargeted(LivingSetAttackTargetEvent event)
{
EntityInfo attackerInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(event.getEntity().getCustomNameTag());
String targetedCustomName;
try {
targetedCustomName = event.getTarget().getCustomName().getUnformattedComponentText();
} catch (NullPointerException e) {
targetedCustomName = null;
}
String attackerCustomName;
try {
attackerCustomName = event.getEntity().getCustomName().getUnformattedComponentText();
} catch (NullPointerException e) {
attackerCustomName = null;
}
EntityInfo attackerInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(attackerCustomName);
if(attackerInfo == null)
{
attackerInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getEntity());
}
EntityInfo targetedInfo;
if(event.getTarget() instanceof EntityPlayer)
if(event.getTarget() instanceof PlayerEntity)
{
targetedInfo = null;
}
else
{
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(event.getTarget().getCustomNameTag());
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(targetedCustomName);
if(targetedInfo == null)
{
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getTarget());
}
}
if((event.getTarget() instanceof EntityPlayer && ((EntityPlayer)event.getTarget()).isCreative())
if((event.getTarget() instanceof PlayerEntity && ((PlayerEntity)event.getTarget()).isCreative())
|| attackerInfo == null
|| attackerInfo.ignoreBattle
|| TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType(attackerInfo.category)
@ -257,7 +290,7 @@ public class BattleManager
if(battle == null)
{
// neither in battle
if(event.getEntity() instanceof EntityPlayer || event.getTarget() instanceof EntityPlayer)
if(event.getEntity() instanceof PlayerEntity || event.getTarget() instanceof PlayerEntity)
{
// at least one is a player, create battle
Collection<Entity> sideA = new ArrayList<Entity>(1);
@ -312,25 +345,23 @@ public class BattleManager
public void cleanup()
{
battleUpdater.setIsRunning(false);
battleUpdater = null;
updaterThread = null;
battleUpdater.setRunning(false);
MinecraftForge.EVENT_BUS.unregister(battleUpdater);
synchronized(battleMap)
{
battleMap.clear();
}
battleUpdater = null;
}
protected void addRecentlyLeftBattle(Combatant c)
{
c.time = System.nanoTime();
Config config = TurnBasedMinecraftMod.proxy.getConfig();
if(c.entity instanceof EntityPlayerMP)
{
TurnBasedMinecraftMod.NWINSTANCE.sendTo(new PacketGeneralMessage("You just left battle! " + config.getLeaveBattleCooldownSeconds() + " seconds until you can attack/be-attacked again!"), (EntityPlayerMP)c.entity);
if(c.entity instanceof ServerPlayerEntity) {
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(()->(ServerPlayerEntity) c.entity), new PacketGeneralMessage("You just left battle! " + config.getLeaveBattleCooldownSeconds() + " seconds until you can attack/be-attacked again!"));
}
synchronized(recentlyLeftBattle)
{
synchronized(recentlyLeftBattle) {
recentlyLeftBattle.put(c.entity.getEntityId(), c);
}
}
@ -346,9 +377,9 @@ public class BattleManager
if(current - entry.getValue().time > TurnBasedMinecraftMod.proxy.getConfig().getLeaveBattleCooldownNanos())
{
iter.remove();
if(entry.getValue().entity instanceof EntityPlayerMP)
if(entry.getValue().entity instanceof ServerPlayerEntity)
{
TurnBasedMinecraftMod.NWINSTANCE.sendTo(new PacketGeneralMessage("Timer ended, you can now attack/be-attacked again."), (EntityPlayerMP)entry.getValue().entity);
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(()->(ServerPlayerEntity)entry.getValue().entity), new PacketGeneralMessage("Timer ended, you can now attack/be-attacked again."));
}
}
}

View file

@ -1,98 +1,35 @@
package com.seodisparate.TurnBasedMinecraft.common;
import java.util.Iterator;
import java.util.Map;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import java.util.concurrent.atomic.AtomicBoolean;
public class BattleUpdater implements Runnable
public class BattleUpdater
{
private BattleManager manager;
private AtomicBoolean isRunning;
private class UpdateRunnable implements Runnable
{
private Battle battle;
private AtomicBoolean finished = new AtomicBoolean(false);
private AtomicBoolean battleFinished = new AtomicBoolean(false);
public UpdateRunnable(Battle battle)
{
this.battle = battle;
}
public boolean isFinished()
{
return finished.get();
}
public boolean isBattleFinished()
{
return battleFinished.get();
}
@Override
public void run()
{
battleFinished.set(battle.update());
finished.set(true);
}
}
private int tick;
private final int tickLimit = 10;
public BattleUpdater(BattleManager manager)
{
this.manager = manager;
isRunning = new AtomicBoolean(true);
tick = 0;
}
@Override
public void run()
{
while(isRunning.get())
{
synchronized(manager.battleMap)
{
for(Iterator<Map.Entry<Integer, Battle>> iter = manager.battleMap.entrySet().iterator(); iter.hasNext();)
{
Map.Entry<Integer, Battle> entry = iter.next();
UpdateRunnable updateRunnable = new UpdateRunnable(entry.getValue());
Thread updateThread = new Thread(updateRunnable);
updateThread.start();
try { updateThread.join(2000); } catch(InterruptedException e){ /* exception ignored */ }
if(!updateRunnable.isFinished())
{
TurnBasedMinecraftMod.logger.warn("Battle (" + entry.getValue().getId() + "; " + entry.getValue().debugLog + ") update hanged for 2 seconds!");
try { updateThread.join(2000); } catch(InterruptedException e){ /* exception ignored */ }
if(!updateRunnable.isFinished())
{
TurnBasedMinecraftMod.logger.warn("Battle (" + entry.getValue().getId() + "; " + entry.getValue().debugLog + ") update hanged for 4 seconds!");
try { updateThread.join(2000); } catch(InterruptedException e){ /* exception ignored */ }
if(!updateRunnable.isFinished())
{
TurnBasedMinecraftMod.logger.error("Battle (" + entry.getValue().getId() + "; " + entry.getValue().debugLog + ") update timed out (6 seconds)!");
updateThread.interrupt();
try { updateThread.join(2000); } catch(InterruptedException e){ /* exception ignored */ }
if(!updateRunnable.isFinished())
{
// TODO this is an ugly fix to a still-not-found freeze bug in Battle.update()
TurnBasedMinecraftMod.logger.error("Battle update will not stop, forcing it to stop (8 seconds)!");
updateThread.stop();
}
}
}
}
if(updateRunnable.isFinished() && updateRunnable.isBattleFinished())
{
iter.remove();
}
}
}
manager.updateRecentlyLeftBattle();
try { Thread.sleep(250); } catch (Throwable t) { /* ignored */ }
}
}
public void setIsRunning(boolean isRunning)
{
public void setRunning(boolean isRunning) {
this.isRunning.set(isRunning);
}
@SubscribeEvent
public void update(TickEvent.ServerTickEvent tickEvent) {
if(tickEvent.phase != TickEvent.Phase.START && isRunning.get() && ++tick > tickLimit) {
tick = 0;
manager.battleMap.entrySet().removeIf(entry -> entry.getValue().update());
manager.updateRecentlyLeftBattle();
}
}
}

View file

@ -4,6 +4,7 @@ import java.util.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.MinecraftForge;
import org.apache.logging.log4j.Logger;
import net.minecraft.client.Minecraft;

View file

@ -862,6 +862,9 @@ public class Config
*/
public EntityInfo getEntityInfo(String classFullName)
{
if(classFullName == null) {
return null;
}
EntityInfo eInfo = entityInfoMap.get(classFullName);
if(eInfo != null)
{
@ -872,18 +875,19 @@ public class Config
protected EntityInfo getEntityInfoReference(String classFullName)
{
if(classFullName == null) {
return null;
}
return entityInfoMap.get(classFullName);
}
protected EntityInfo getMatchingEntityInfo(Object entity)
{
if(entity == null)
{
if(entity == null) {
return null;
}
EntityInfo matching = entityInfoMap.get(entity.getClass().getName());
if(matching != null && matching.classType.isInstance(entity))
{
if(matching != null && matching.classType.isInstance(entity)) {
return matching;
}
return null;
@ -896,6 +900,9 @@ public class Config
*/
public EntityInfo getCustomEntityInfo(String customName)
{
if(customName == null) {
return null;
}
EntityInfo eInfo = customEntityInfoMap.get(customName);
if(eInfo != null)
{
@ -906,6 +913,9 @@ public class Config
protected EntityInfo getCustomEntityInfoReference(String customName)
{
if(customName == null) {
return null;
}
return customEntityInfoMap.get(customName);
}