WIP campaign stat tracking (not displayed yet)
This commit is contained in:
@@ -187,7 +187,7 @@ public class Control implements ApplicationListener, Loadable{
|
|||||||
Events.on(GameOverEvent.class, e -> {
|
Events.on(GameOverEvent.class, e -> {
|
||||||
if(state.isCampaign() && !net.client() && !headless){
|
if(state.isCampaign() && !net.client() && !headless){
|
||||||
|
|
||||||
//save gameover sate immediately
|
//save gameover state immediately
|
||||||
if(saves.getCurrent() != null){
|
if(saves.getCurrent() != null){
|
||||||
saves.getCurrent().save();
|
saves.getCurrent().save();
|
||||||
}
|
}
|
||||||
@@ -285,7 +285,12 @@ public class Control implements ApplicationListener, Loadable{
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(SaveWriteEvent.class, e -> forcePlaceAll());
|
Events.on(SaveWriteEvent.class, e -> {
|
||||||
|
if(!net.client() && state.isCampaign()){
|
||||||
|
state.getPlanet().saveStats();
|
||||||
|
}
|
||||||
|
forcePlaceAll();
|
||||||
|
});
|
||||||
Events.on(HostEvent.class, e -> forcePlaceAll());
|
Events.on(HostEvent.class, e -> forcePlaceAll());
|
||||||
Events.on(HostEvent.class, e -> {
|
Events.on(HostEvent.class, e -> {
|
||||||
state.set(State.playing);
|
state.set(State.playing);
|
||||||
|
|||||||
@@ -135,6 +135,10 @@ public class Logic implements ApplicationListener{
|
|||||||
if(!net.client() && e.sector.planet.generator != null){
|
if(!net.client() && e.sector.planet.generator != null){
|
||||||
e.sector.planet.generator.onSectorCaptured(e.sector);
|
e.sector.planet.generator.onSectorCaptured(e.sector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().sectorsCaptured ++;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(SectorLoseEvent.class, e -> {
|
Events.on(SectorLoseEvent.class, e -> {
|
||||||
@@ -157,38 +161,71 @@ public class Logic implements ApplicationListener{
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
Events.on(BlockBuildEndEvent.class, e -> {
|
Events.on(BlockBuildEndEvent.class, e -> {
|
||||||
if(e.team == state.rules.defaultTeam){
|
|
||||||
|
if((e.team == state.rules.defaultTeam || e.unit != null && e.unit.team == state.rules.defaultTeam)){
|
||||||
if(e.breaking){
|
if(e.breaking){
|
||||||
state.stats.buildingsDeconstructed++;
|
state.stats.buildingsDeconstructed++;
|
||||||
}else{
|
}else{
|
||||||
state.stats.buildingsBuilt++;
|
state.stats.buildingsBuilt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
(e.breaking ? state.getPlanet().stats().buildingsDeconstructed : state.getPlanet().stats().buildingsBuilt).increment(e.tile.block());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(BlockDestroyEvent.class, e -> {
|
Events.on(BlockDestroyEvent.class, e -> {
|
||||||
if(e.tile.team() == state.rules.defaultTeam){
|
if(e.tile.team() == state.rules.defaultTeam){
|
||||||
state.stats.buildingsDestroyed ++;
|
state.stats.buildingsDestroyed ++;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Events.on(BlockDestroyEvent.class, e -> {
|
if(checkCampaignStats()){
|
||||||
if(e.tile.team() != state.rules.defaultTeam){
|
state.getPlanet().stats().buildingsDestroyed.increment(e.tile.block());
|
||||||
|
}
|
||||||
|
}else{ //...should derelict blocks count as 'destroyed'? technically, they could be destroyed by the enemy, but that is very rare
|
||||||
state.stats.destroyedBlockCount.increment(e.tile.block());
|
state.stats.destroyedBlockCount.increment(e.tile.block());
|
||||||
|
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().enemyBuildingsDestroyed.increment(e.tile.block());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(UnitDestroyEvent.class, e -> {
|
Events.on(UnitDestroyEvent.class, e -> {
|
||||||
if(e.unit.team() != state.rules.defaultTeam){
|
if(e.unit.team() != state.rules.defaultTeam){
|
||||||
state.stats.enemyUnitsDestroyed ++;
|
state.stats.enemyUnitsDestroyed ++;
|
||||||
|
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().enemyUnitsDestroyed.increment(e.unit.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(UnitCreateEvent.class, e -> {
|
Events.on(UnitCreateEvent.class, e -> {
|
||||||
if(e.unit.team == state.rules.defaultTeam){
|
if(e.unit.team == state.rules.defaultTeam){
|
||||||
state.stats.unitsCreated++;
|
state.stats.unitsCreated++;
|
||||||
|
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().unitsProduced.increment(e.unit.type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Events.on(WaveEvent.class, e -> {
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().wavesLasted ++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Events.on(GameOverEvent.class, e -> {
|
||||||
|
if(checkCampaignStats()){
|
||||||
|
state.getPlanet().stats().sectorsLost ++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkCampaignStats(){
|
||||||
|
return state.isCampaign() && !net.client();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkOverlappingPlans(Team team, Tile tile){
|
private void checkOverlappingPlans(Team team, Tile tile){
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package mindustry.game;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
import mindustry.world.*;
|
||||||
|
|
||||||
|
/** Statistics for a specific planet's campaign. */
|
||||||
|
public class CampaignStats{
|
||||||
|
/** Enemy units destroyed by type. */
|
||||||
|
public ObjectIntMap<UnitType> enemyUnitsDestroyed = new ObjectIntMap<>();
|
||||||
|
/** Record of enemy blocks that have been destroyed (from any source) by count. */
|
||||||
|
public ObjectIntMap<Block> enemyBuildingsDestroyed = new ObjectIntMap<>();
|
||||||
|
/** Player team units produced by type. */
|
||||||
|
public ObjectIntMap<UnitType> unitsProduced = new ObjectIntMap<>();
|
||||||
|
/** Record of blocks that have been placed by count. */
|
||||||
|
public ObjectIntMap<Block> buildingsBuilt = new ObjectIntMap<>();
|
||||||
|
/** Record of blocks that have been placed by count. */
|
||||||
|
public ObjectIntMap<Block> buildingsDeconstructed = new ObjectIntMap<>();
|
||||||
|
/** Record of blocks that have been placed by count. */
|
||||||
|
public ObjectIntMap<Block> buildingsDestroyed = new ObjectIntMap<>();
|
||||||
|
/** Total campaign playtime in milliseconds. */
|
||||||
|
public long playtime;
|
||||||
|
/** Total game-overs. */
|
||||||
|
public int sectorsLost;
|
||||||
|
/** Total times a sector has been captured. If you lose (or get invaded) and re-capture something, this still counts. */
|
||||||
|
public int sectorsCaptured;
|
||||||
|
/** Total waves lasted. */
|
||||||
|
public int wavesLasted;
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ public class GameStats{
|
|||||||
/** Record of enemy blocks that have been destroyed (from any source) by count. */
|
/** Record of enemy blocks that have been destroyed (from any source) by count. */
|
||||||
public ObjectIntMap<Block> destroyedBlockCount = new ObjectIntMap<>();
|
public ObjectIntMap<Block> destroyedBlockCount = new ObjectIntMap<>();
|
||||||
/**
|
/**
|
||||||
* Record of items that have entered the core through transport blocks. Used for objectives only.
|
* Record of items that have entered the core through transport blocks. Used for tutorial objectives only.
|
||||||
* This can easily be ""spoofed"" with unloaders, so don't use it for anything remotely important.
|
* This can easily be ""spoofed"" with unloaders, so don't use it for anything remotely important.
|
||||||
* */
|
* */
|
||||||
public ObjectIntMap<Item> coreItemCount = new ObjectIntMap<>();
|
public ObjectIntMap<Item> coreItemCount = new ObjectIntMap<>();
|
||||||
|
|||||||
@@ -187,7 +187,11 @@ public class Saves{
|
|||||||
if(current != null && state.isGame()
|
if(current != null && state.isGame()
|
||||||
&& !(state.isPaused() && Core.scene.hasDialog())){
|
&& !(state.isPaused() && Core.scene.hasDialog())){
|
||||||
if(lastTimestamp != 0){
|
if(lastTimestamp != 0){
|
||||||
totalPlaytime += Time.timeSinceMillis(lastTimestamp);
|
long change = Time.timeSinceMillis(lastTimestamp);
|
||||||
|
totalPlaytime += change;
|
||||||
|
if(state.isCampaign()){
|
||||||
|
state.getPlanet().stats().playtime += change;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastTimestamp = Time.millis();
|
lastTimestamp = Time.millis();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ public class Planet extends UnlockableContent{
|
|||||||
/** Loads the planet grid outline mesh. Clientside only. */
|
/** Loads the planet grid outline mesh. Clientside only. */
|
||||||
public Prov<Mesh> gridMeshLoader = () -> MeshBuilder.buildPlanetGrid(grid, outlineColor, outlineRad * radius);
|
public Prov<Mesh> gridMeshLoader = () -> MeshBuilder.buildPlanetGrid(grid, outlineColor, outlineRad * radius);
|
||||||
|
|
||||||
|
/** If set, this planet will have the same stats as its parent. Use for shared campaigns. */
|
||||||
|
public @Nullable Planet statParent;
|
||||||
|
|
||||||
/** Planets that are allowed to update at the same time as this one for background calculations. */
|
/** Planets that are allowed to update at the same time as this one for background calculations. */
|
||||||
public ObjectSet<Planet> updateGroup = new ObjectSet<>();
|
public ObjectSet<Planet> updateGroup = new ObjectSet<>();
|
||||||
/** Global difficulty/modifier settings for this planet's campaign. */
|
/** Global difficulty/modifier settings for this planet's campaign. */
|
||||||
@@ -178,6 +181,9 @@ public class Planet extends UnlockableContent{
|
|||||||
/** Data indicating attack sector positions and sector mappings. */
|
/** Data indicating attack sector positions and sector mappings. */
|
||||||
public @Nullable PlanetData data;
|
public @Nullable PlanetData data;
|
||||||
|
|
||||||
|
/** Statistics of this planet campaign. If statParent is not null, this planet shares the same stats as the parent. */
|
||||||
|
private CampaignStats campaignStats = new CampaignStats();
|
||||||
|
|
||||||
public Planet(String name, Planet parent, float radius){
|
public Planet(String name, Planet parent, float radius){
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
@@ -228,6 +234,34 @@ public class Planet extends UnlockableContent{
|
|||||||
campaignRules = Core.settings.getJson(name + "-campaign-rules", CampaignRules.class, () -> campaignRules);
|
campaignRules = Core.settings.getJson(name + "-campaign-rules", CampaignRules.class, () -> campaignRules);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CampaignStats stats(){
|
||||||
|
return statParent != null ? statParent.campaignStats : campaignStats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadStats(){
|
||||||
|
//there is no need to load stats if the parent's ones are used
|
||||||
|
if(statParent == null){
|
||||||
|
campaignStats = Core.settings.getJson(name + "-campaign-stats", CampaignStats.class, CampaignStats::new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveStats(){
|
||||||
|
if(statParent != null && statParent != this){
|
||||||
|
statParent.saveStats();
|
||||||
|
}else{
|
||||||
|
Core.settings.putJson(name + "-campaign-stats", campaignStats);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearStats(){
|
||||||
|
if(statParent != null && statParent != this){
|
||||||
|
statParent.clearStats();
|
||||||
|
}else{
|
||||||
|
campaignStats = new CampaignStats();
|
||||||
|
saveStats();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable Sector getStartSector(){
|
public @Nullable Sector getStartSector(){
|
||||||
return sectors.size == 0 ? null : sectors.get(startSector);
|
return sectors.size == 0 ? null : sectors.get(startSector);
|
||||||
}
|
}
|
||||||
@@ -391,6 +425,7 @@ public class Planet extends UnlockableContent{
|
|||||||
public void init(){
|
public void init(){
|
||||||
applyDefaultRules(campaignRules);
|
applyDefaultRules(campaignRules);
|
||||||
loadRules();
|
loadRules();
|
||||||
|
loadStats();
|
||||||
|
|
||||||
if(techTree == null){
|
if(techTree == null){
|
||||||
techTree = TechTree.roots.find(n -> n.planet == this);
|
techTree = TechTree.roots.find(n -> n.planet == this);
|
||||||
|
|||||||
@@ -36,7 +36,13 @@ public class PausedDialog extends BaseDialog{
|
|||||||
}).size(70f).tooltip("@customize").visible(() -> state.rules.allowEditRules && (net.server() || !net.active()));
|
}).size(70f).tooltip("@customize").visible(() -> state.rules.allowEditRules && (net.server() || !net.active()));
|
||||||
})).grow().row();
|
})).grow().row();
|
||||||
|
|
||||||
shown(this::rebuild);
|
shown(() -> {
|
||||||
|
rebuild();
|
||||||
|
|
||||||
|
if(state.isCampaign()){
|
||||||
|
state.getPlanet().saveStats();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
addCloseListener();
|
addCloseListener();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ public class SettingsMenuDialog extends BaseDialog{
|
|||||||
t.button("@settings.clearcampaignsaves", Icon.trash, style, () -> {
|
t.button("@settings.clearcampaignsaves", Icon.trash, style, () -> {
|
||||||
ui.showConfirm("@confirm", "@settings.clearcampaignsaves.confirm", () -> {
|
ui.showConfirm("@confirm", "@settings.clearcampaignsaves.confirm", () -> {
|
||||||
for(var planet : content.planets()){
|
for(var planet : content.planets()){
|
||||||
|
planet.clearStats();
|
||||||
for(var sec : planet.sectors){
|
for(var sec : planet.sectors){
|
||||||
sec.clearInfo();
|
sec.clearInfo();
|
||||||
if(sec.save != null){
|
if(sec.save != null){
|
||||||
|
|||||||
Reference in New Issue
Block a user