Sieges: reinforcements log in for registered clans and log out after, walls excluded, siege state/skills set for bots; bots count as online clan members (clan skills); dashboard telemetry panel
This commit is contained in:
@@ -38,6 +38,8 @@ canvas{width:100%;height:100%;display:block;background:#0d1014}
|
|||||||
<div class="sub">живой срез мира, обновление каждые 5 сек</div>
|
<div class="sub">живой срез мира, обновление каждые 5 сек</div>
|
||||||
<div class="lbl">Итого</div>
|
<div class="lbl">Итого</div>
|
||||||
<div id="stats"></div>
|
<div id="stats"></div>
|
||||||
|
<div class="lbl">Что реально сделали</div>
|
||||||
|
<div id="telemetry" class="sub">…</div>
|
||||||
<div class="lbl">Фильтр</div>
|
<div class="lbl">Фильтр</div>
|
||||||
<input id="q" placeholder="поиск по нику...">
|
<input id="q" placeholder="поиск по нику...">
|
||||||
<div style="margin-top:6px">
|
<div style="margin-top:6px">
|
||||||
@@ -180,6 +182,17 @@ document.getElementById('pGo').onclick=()=>{
|
|||||||
})};
|
})};
|
||||||
|
|
||||||
refresh();setInterval(refresh,5000);
|
refresh();setInterval(refresh,5000);
|
||||||
|
function telemetry(){
|
||||||
|
fetch('/api/stats').then(r=>r.json()).then(t=>{
|
||||||
|
const keys=['kills','exp','loot','itemsSold','adenaEarned','adenaSpent','stores','skillsCast','rests','lines','replies','parties','migrations','professions','sieges','pvpKills','deaths'];
|
||||||
|
let h='';
|
||||||
|
keys.forEach(k=>{h+='<div class="stat"><span>'+k+'</span><b>'+(t[k]??0)+'</b></div>';});
|
||||||
|
h+='<div class="stat"><span>сейчас</span><b>бой '+t.fighting+' · сидят '+t.sitting+' · торгуют '+t.trading+' · в пати '+t.inParty+' · на осаде '+t.besieging+'</b></div>';
|
||||||
|
h+='<div class="stat"><span>аптайм</span><b>'+t.uptimeMin+' мин</b></div>';
|
||||||
|
document.getElementById('telemetry').innerHTML=h;
|
||||||
|
}).catch(()=>{});
|
||||||
|
}
|
||||||
|
telemetry();setInterval(telemetry,10000);
|
||||||
window.addEventListener('resize',draw);
|
window.addEventListener('resize',draw);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+1
@@ -79,6 +79,7 @@ public class FakePlayerBotState
|
|||||||
public boolean giftedStock = false;
|
public boolean giftedStock = false;
|
||||||
|
|
||||||
// --- siege ---
|
// --- siege ---
|
||||||
|
public boolean temporary = false; // Logged in on demand for a siege; leaves the world afterwards.
|
||||||
public byte siegeSide = 0; // 0 none, 1 attacker, 2 defender.
|
public byte siegeSide = 0; // 0 none, 1 attacker, 2 defender.
|
||||||
public int siegeCastleId = 0;
|
public int siegeCastleId = 0;
|
||||||
public long siegeNextThink = 0;
|
public long siegeNextThink = 0;
|
||||||
|
|||||||
+54
-2
@@ -191,7 +191,9 @@ public class FakePlayerHeadlessManager
|
|||||||
|
|
||||||
// Believable player title instead of a personality label.
|
// Believable player title instead of a personality label.
|
||||||
player.setTitle(TITLES[Rnd.get(TITLES.length)]);
|
player.setTitle(TITLES[Rnd.get(TITLES.length)]);
|
||||||
// Restore clan membership so crests, clan wars and sieges work like for real players.
|
// The bot is online for the engine (clan member lists, sieges, parties count it like a logged in player).
|
||||||
|
player.setOnlineStatus(true, false);
|
||||||
|
// Restore clan membership so crests, clan skills, clan wars and sieges work like for real players.
|
||||||
if (player.getClanId() > 0)
|
if (player.getClanId() > 0)
|
||||||
{
|
{
|
||||||
final Clan clan = ClanTable.getInstance().getClan(player.getClanId());
|
final Clan clan = ClanTable.getInstance().getClan(player.getClanId());
|
||||||
@@ -200,6 +202,11 @@ public class FakePlayerHeadlessManager
|
|||||||
player.setClan(clan);
|
player.setClan(clan);
|
||||||
player.setPledgeType(0);
|
player.setPledgeType(0);
|
||||||
player.setPowerGrade((clan.getLeaderId() == player.getObjectId()) ? 1 : 6);
|
player.setPowerGrade((clan.getLeaderId() == player.getObjectId()) ? 1 : 6);
|
||||||
|
final org.l2jmobius.gameserver.entity.clan.ClanMember member = clan.getClanMember(player.getObjectId());
|
||||||
|
if (member != null)
|
||||||
|
{
|
||||||
|
member.setPlayer(player); // Clan skills, siege skills for the leader, "online" for the clan.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Place the bot in a level appropriate farming zone (shared zone table). Clanmates of a
|
// Place the bot in a level appropriate farming zone (shared zone table). Clanmates of a
|
||||||
@@ -247,6 +254,16 @@ public class FakePlayerHeadlessManager
|
|||||||
* @return the headless player, or null.
|
* @return the headless player, or null.
|
||||||
*/
|
*/
|
||||||
public Player ensureOnline(int charId)
|
public Player ensureOnline(int charId)
|
||||||
|
{
|
||||||
|
return ensureOnline(charId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param charId the character id.
|
||||||
|
* @param temporary true when the bot should log out again after its job (siege reinforcement).
|
||||||
|
* @return the headless player, or null.
|
||||||
|
*/
|
||||||
|
public Player ensureOnline(int charId, boolean temporary)
|
||||||
{
|
{
|
||||||
if (charId <= 0)
|
if (charId <= 0)
|
||||||
{
|
{
|
||||||
@@ -266,11 +283,46 @@ public class FakePlayerHeadlessManager
|
|||||||
final Player bot = spawnOne(charId);
|
final Player bot = spawnOne(charId);
|
||||||
if (bot != null)
|
if (bot != null)
|
||||||
{
|
{
|
||||||
LOGGER.info(getClass().getSimpleName() + ": " + bot.getName() + " logged in on demand (" + _bots.size() + " headless players now).");
|
final FakePlayerBotState state = stateOf(bot);
|
||||||
|
if ((state != null) && temporary)
|
||||||
|
{
|
||||||
|
state.temporary = true;
|
||||||
|
}
|
||||||
|
LOGGER.info(getClass().getSimpleName() + ": " + bot.getName() + " logged in on demand" + (temporary ? " for a siege" : "") + " (" + _bots.size() + " headless players now).");
|
||||||
}
|
}
|
||||||
return bot;
|
return bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a temporary bot out (siege reinforcements after the battle): stores it and removes it from the world.
|
||||||
|
* @param bot the bot.
|
||||||
|
*/
|
||||||
|
public void despawn(Player bot)
|
||||||
|
{
|
||||||
|
final FakePlayerBotState state = stateOf(bot);
|
||||||
|
if ((state == null) || !state.temporary || (state.siegeSide != 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closeStore(bot);
|
||||||
|
if (bot.getParty() != null)
|
||||||
|
{
|
||||||
|
bot.leaveParty();
|
||||||
|
}
|
||||||
|
_states.remove(bot.getObjectId());
|
||||||
|
_bots.remove(bot);
|
||||||
|
bot.setOnlineStatus(false, false);
|
||||||
|
bot.deleteMe();
|
||||||
|
LOGGER.info(getClass().getSimpleName() + ": " + bot.getName() + " logged out (" + _bots.size() + " headless players now).");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
LOGGER.log(Level.WARNING, getClass().getSimpleName() + ": Could not log out " + bot.getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======================== Registry ========================
|
// ======================== Registry ========================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+69
-6
@@ -287,17 +287,60 @@ public class FakePlayerSiegeManager
|
|||||||
}
|
}
|
||||||
_battles.put(castle.getResidenceId(), battle);
|
_battles.put(castle.getResidenceId(), battle);
|
||||||
|
|
||||||
|
// Reinforcements: a registered clan brings its strongest members even if they were not in the
|
||||||
|
// random population sample (they log out again after the battle).
|
||||||
|
final Set<Integer> battleClans = new HashSet<>(battle.attackerClans);
|
||||||
|
battleClans.addAll(battle.defenderClans);
|
||||||
|
for (int clanId : battleClans)
|
||||||
|
{
|
||||||
|
final Clan clan = ClanTable.getInstance().getClan(clanId);
|
||||||
|
if (clan == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int online = 0;
|
||||||
|
for (Player bot : FakePlayerHeadlessManager.getInstance().bots())
|
||||||
|
{
|
||||||
|
if ((bot.getClanId() == clanId) && (bot.getLevel() >= (MIN_LEVEL - 10)))
|
||||||
|
{
|
||||||
|
online++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final List<org.l2jmobius.gameserver.entity.clan.ClanMember> strongest = new ArrayList<>(clan.getMembers());
|
||||||
|
strongest.sort((a, b) -> Integer.compare(b.getLevel(), a.getLevel()));
|
||||||
|
for (org.l2jmobius.gameserver.entity.clan.ClanMember member : strongest)
|
||||||
|
{
|
||||||
|
if ((online >= 8) || (member.getLevel() < MIN_LEVEL))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (FakePlayerHeadlessManager.getInstance().ensureOnline(member.getObjectId(), true) != null)
|
||||||
|
{
|
||||||
|
online++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FakePlayerHeadlessManager.getInstance().ensureOnline(clan.getLeaderId(), true);
|
||||||
|
}
|
||||||
|
|
||||||
// Participants: online headless members of the registered clans.
|
// Participants: online headless members of the registered clans.
|
||||||
final Map<Integer, Integer> perClan = new HashMap<>();
|
final Map<Integer, Integer> perClan = new HashMap<>();
|
||||||
|
int members = 0;
|
||||||
|
int tooLow = 0;
|
||||||
for (Player bot : FakePlayerHeadlessManager.getInstance().bots())
|
for (Player bot : FakePlayerHeadlessManager.getInstance().bots())
|
||||||
{
|
{
|
||||||
final int clanId = bot.getClanId();
|
final int clanId = bot.getClanId();
|
||||||
final boolean attacker = battle.attackerClans.contains(clanId);
|
final boolean attacker = battle.attackerClans.contains(clanId);
|
||||||
final boolean defender = battle.defenderClans.contains(clanId);
|
final boolean defender = battle.defenderClans.contains(clanId);
|
||||||
if ((!attacker && !defender) || (bot.getLevel() < (MIN_LEVEL - 10)))
|
if (!attacker && !defender)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
members++;
|
||||||
|
if (bot.getLevel() < (MIN_LEVEL - 10))
|
||||||
|
{
|
||||||
|
tooLow++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
final int count = perClan.getOrDefault(clanId, 0);
|
final int count = perClan.getOrDefault(clanId, 0);
|
||||||
if ((count >= MAX_PER_CLAN) && !bot.isClanLeader())
|
if ((count >= MAX_PER_CLAN) && !bot.isClanLeader())
|
||||||
{
|
{
|
||||||
@@ -315,6 +358,12 @@ public class FakePlayerSiegeManager
|
|||||||
state.siegesJoined.incrementAndGet();
|
state.siegesJoined.incrementAndGet();
|
||||||
state.action((attacker ? "siege attack " : "siege defend ") + castle.getName());
|
state.action((attacker ? "siege attack " : "siege defend ") + castle.getName());
|
||||||
bot.setSiegeState(state.siegeSide);
|
bot.setSiegeState(state.siegeSide);
|
||||||
|
bot.setSiegeSide(castle.getResidenceId());
|
||||||
|
if (bot.isClanLeader() && (bot.getKnownSkill(CommonSkill.SEAL_OF_RULER.getId()) == null))
|
||||||
|
{
|
||||||
|
SiegeManager.getInstance().addSiegeSkills(bot);
|
||||||
|
}
|
||||||
|
bot.updateUserInfo();
|
||||||
FakePlayerBotContext.setPlan(state.seedId, "siege", 3 * 3600000L);
|
FakePlayerBotContext.setPlan(state.seedId, "siege", 3 * 3600000L);
|
||||||
FakePlayerBotContext.setSlot(state.seedId, "castle", castle.getName());
|
FakePlayerBotContext.setSlot(state.seedId, "castle", castle.getName());
|
||||||
battle.participants.add(bot);
|
battle.participants.add(bot);
|
||||||
@@ -345,7 +394,7 @@ public class FakePlayerSiegeManager
|
|||||||
ThreadPool.schedule(() -> cry(bot, seam), 6000 + Rnd.get(4000));
|
ThreadPool.schedule(() -> cry(bot, seam), 6000 + Rnd.get(4000));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOGGER.info(getClass().getSimpleName() + ": Siege of " + castle.getName() + " - " + battle.participants.size() + " bots joined (attacker clans " + battle.attackerClans + ", defender clans " + battle.defenderClans + ").");
|
LOGGER.info(getClass().getSimpleName() + ": Siege of " + castle.getName() + " - " + battle.participants.size() + " bots joined of " + members + " clan members online (" + tooLow + " too low), attacker clans " + battle.attackerClans + ", defender clans " + battle.defenderClans + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -365,7 +414,7 @@ public class FakePlayerSiegeManager
|
|||||||
double best = -1;
|
double best = -1;
|
||||||
for (Door door : castle.getDoors())
|
for (Door door : castle.getDoors())
|
||||||
{
|
{
|
||||||
if (!door.isShowHp())
|
if (!door.isShowHp() || door.isWall())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -487,7 +536,7 @@ public class FakePlayerSiegeManager
|
|||||||
Door gate = null;
|
Door gate = null;
|
||||||
for (Door door : battle.castle.getDoors())
|
for (Door door : battle.castle.getDoors())
|
||||||
{
|
{
|
||||||
if (door.isOpen() || door.isDead() || !door.isAutoAttackable(bot))
|
if (door.isOpen() || door.isDead() || door.isWall() || !door.isAutoAttackable(bot))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -563,13 +612,27 @@ public class FakePlayerSiegeManager
|
|||||||
}
|
}
|
||||||
state.siegeSide = 0;
|
state.siegeSide = 0;
|
||||||
state.siegeCastleId = 0;
|
state.siegeCastleId = 0;
|
||||||
|
bot.setSiegeState((byte) 0);
|
||||||
|
bot.setSiegeSide(0);
|
||||||
|
bot.setInSiege(false);
|
||||||
|
bot.updateUserInfo();
|
||||||
FakePlayerBotContext.setPlan(state.seedId, "farm", 0);
|
FakePlayerBotContext.setPlan(state.seedId, "farm", 0);
|
||||||
FakePlayerBotContext.setEvent(state.seedId, "siege_finished");
|
FakePlayerBotContext.setEvent(state.seedId, "siege_finished");
|
||||||
state.action("siege over");
|
state.action("siege over");
|
||||||
// Back to the farming spot after a while (the engine already sends everybody to town).
|
// Back to the farming spot after a while (the engine already sends everybody to town);
|
||||||
|
// reinforcements that only came for the battle log out instead.
|
||||||
ThreadPool.schedule(() ->
|
ThreadPool.schedule(() ->
|
||||||
{
|
{
|
||||||
if (!bot.isDead() && (FakePlayerHeadlessManager.getInstance().stateOf(bot) != null) && (FakePlayerHeadlessManager.getInstance().stateOf(bot).siegeSide == 0))
|
final FakePlayerBotState current = FakePlayerHeadlessManager.getInstance().stateOf(bot);
|
||||||
|
if ((current == null) || (current.siegeSide != 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (current.temporary)
|
||||||
|
{
|
||||||
|
FakePlayerHeadlessManager.getInstance().despawn(bot);
|
||||||
|
}
|
||||||
|
else if (!bot.isDead())
|
||||||
{
|
{
|
||||||
FakePlayerHeadlessManager.getInstance().returnToSpot(bot);
|
FakePlayerHeadlessManager.getInstance().returnToSpot(bot);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user