Progress on sector state

This commit is contained in:
Anuken
2020-05-30 21:04:41 -04:00
parent 8a4824e72d
commit 0842c3f0a0
20 changed files with 314 additions and 211 deletions

View File

@@ -222,6 +222,8 @@ public class EntityProcess extends BaseProcessor{
Array<Svar> syncedFields = new Array<>(); Array<Svar> syncedFields = new Array<>();
Array<Svar> allFields = new Array<>(); Array<Svar> allFields = new Array<>();
boolean isSync = components.contains(s -> s.name().contains("Sync"));
//add all components //add all components
for(Stype comp : components){ for(Stype comp : components){
@@ -257,7 +259,7 @@ public class EntityProcess extends BaseProcessor{
allFields.add(f); allFields.add(f);
//add extra sync fields //add extra sync fields
if(f.has(SyncField.class)){ if(f.has(SyncField.class) && isSync){
if(!f.tname().toString().equals("float")) err("All SyncFields must be of type float", f); if(!f.tname().toString().equals("float")) err("All SyncFields must be of type float", f);
syncedFields.add(f); syncedFields.add(f);

View File

@@ -12,7 +12,7 @@ mindustry.entities.comp.PlayerComp=8
mindustry.entities.comp.PuddleComp=9 mindustry.entities.comp.PuddleComp=9
mindustry.entities.comp.TileComp=10 mindustry.entities.comp.TileComp=10
mindustry.type.Weather.WeatherComp=11 mindustry.type.Weather.WeatherComp=11
mindustry.world.blocks.storage.LaunchPad.LaunchPayloadComp=12 mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=12
oculon=13 oculon=13
phantom=14 phantom=14
tau=19 tau=19

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -24,70 +24,72 @@ const extend = function(classType, params){
const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer}))
Call = Packages.mindustry.gen.Call Call = Packages.mindustry.gen.Call
importPackage(Packages.mindustry.game) importPackage(Packages.mindustry.graphics.g3d)
importPackage(Packages.arc.func) importPackage(Packages.mindustry.ctype)
importPackage(Packages.mindustry.entities)
importPackage(Packages.mindustry.gen) importPackage(Packages.mindustry.gen)
importPackage(Packages.mindustry.core)
importPackage(Packages.mindustry.world.blocks.storage)
importPackage(Packages.mindustry.ui.dialogs)
importPackage(Packages.arc.scene.ui)
importPackage(Packages.mindustry.world.blocks.defense.turrets)
importPackage(Packages.mindustry.world.blocks.distribution)
importPackage(Packages.mindustry.ui)
importPackage(Packages.mindustry.content)
importPackage(Packages.mindustry.world.blocks.liquid)
importPackage(Packages.arc.struct)
importPackage(Packages.arc.scene.ui.layout)
importPackage(Packages.mindustry.world.modules)
importPackage(Packages.arc.util)
importPackage(Packages.arc.graphics)
importPackage(Packages.mindustry.entities.def)
importPackage(Packages.mindustry.maps.generators)
importPackage(Packages.arc.scene.actions) importPackage(Packages.arc.scene.actions)
importPackage(Packages.mindustry.graphics)
importPackage(Packages.mindustry.entities.bullet)
importPackage(Packages.mindustry.world.blocks.legacy)
importPackage(Packages.mindustry.world.blocks.experimental)
importPackage(Packages.mindustry.editor) importPackage(Packages.mindustry.editor)
importPackage(Packages.mindustry.type)
importPackage(Packages.arc.scene.ui)
importPackage(Packages.arc.math.geom)
importPackage(Packages.mindustry.game)
importPackage(Packages.mindustry.maps.filters)
importPackage(Packages.arc.struct)
importPackage(Packages.arc.scene.style)
importPackage(Packages.mindustry.ui.dialogs)
importPackage(Packages.mindustry.entities.comp)
importPackage(Packages.mindustry.world.blocks.defense.turrets)
importPackage(Packages.mindustry.async)
importPackage(Packages.mindustry.world.blocks.distribution)
importPackage(Packages.mindustry.world.blocks.environment)
importPackage(Packages.mindustry.world.blocks.campaign)
importPackage(Packages.mindustry.world.blocks.liquid)
importPackage(Packages.mindustry.ui)
importPackage(Packages.mindustry.world.blocks.production)
importPackage(Packages.mindustry.ai)
importPackage(Packages.mindustry.world.blocks.defense)
importPackage(Packages.mindustry.world.meta)
importPackage(Packages.mindustry.world.blocks.legacy)
importPackage(Packages.mindustry.world.blocks.units)
importPackage(Packages.arc.graphics)
importPackage(Packages.arc.func)
importPackage(Packages.mindustry.content)
importPackage(Packages.mindustry.world.blocks.power) importPackage(Packages.mindustry.world.blocks.power)
importPackage(Packages.mindustry.ui.layout) importPackage(Packages.mindustry.world.blocks)
importPackage(Packages.arc.scene.event)
importPackage(Packages.mindustry.logic)
importPackage(Packages.arc.math)
importPackage(Packages.mindustry.world)
importPackage(Packages.mindustry.maps)
importPackage(Packages.mindustry.maps.generators)
importPackage(Packages.mindustry.world.meta.values)
importPackage(Packages.mindustry.entities)
importPackage(Packages.arc.util)
importPackage(Packages.mindustry.graphics)
importPackage(Packages.mindustry.world.modules)
importPackage(Packages.mindustry.world.blocks.sandbox) importPackage(Packages.mindustry.world.blocks.sandbox)
importPackage(Packages.mindustry.input) importPackage(Packages.mindustry.input)
importPackage(Packages.mindustry.world.consumers)
importPackage(Packages.mindustry.ui.fragments)
importPackage(Packages.mindustry.ai.formations)
importPackage(Packages.mindustry.type)
importPackage(Packages.mindustry.world.blocks.production)
importPackage(Packages.arc.scene.event)
importPackage(Packages.arc.math)
importPackage(Packages.arc.scene.utils)
importPackage(Packages.mindustry.world.blocks.defense)
importPackage(Packages.mindustry.graphics.g3d)
importPackage(Packages.mindustry.world.meta)
importPackage(Packages.mindustry.world.blocks.payloads)
importPackage(Packages.mindustry.world)
importPackage(Packages.mindustry.async)
importPackage(Packages.arc.scene.style)
importPackage(Packages.mindustry.world.blocks)
importPackage(Packages.arc.math.geom)
importPackage(Packages.mindustry.ai)
importPackage(Packages.mindustry.maps.filters)
importPackage(Packages.arc.graphics.g2d)
importPackage(Packages.mindustry.ai.formations.patterns)
importPackage(Packages.mindustry.world.blocks.environment)
importPackage(Packages.mindustry)
importPackage(Packages.mindustry.entities.units) importPackage(Packages.mindustry.entities.units)
importPackage(Packages.mindustry.ctype) importPackage(Packages.arc.scene.ui.layout)
importPackage(Packages.mindustry.ai.types) importPackage(Packages.mindustry.ai.types)
importPackage(Packages.mindustry.maps) importPackage(Packages.mindustry.ai.formations.patterns)
importPackage(Packages.mindustry.world.meta.values) importPackage(Packages.arc.scene.utils)
importPackage(Packages.mindustry.world.producers) importPackage(Packages.mindustry.ai.formations)
importPackage(Packages.mindustry.world.blocks.units) importPackage(Packages.mindustry.ui.fragments)
importPackage(Packages.mindustry.world.blocks.experimental)
importPackage(Packages.mindustry.world.blocks.storage)
importPackage(Packages.mindustry.audio)
importPackage(Packages.mindustry.ui.layout)
importPackage(Packages.mindustry.entities.bullet)
importPackage(Packages.mindustry.world.consumers)
importPackage(Packages.mindustry.core)
importPackage(Packages.arc.scene) importPackage(Packages.arc.scene)
importPackage(Packages.mindustry.maps.planet) importPackage(Packages.mindustry)
importPackage(Packages.arc) importPackage(Packages.arc)
importPackage(Packages.mindustry.world.blocks.logic) importPackage(Packages.mindustry.world.blocks.payloads)
importPackage(Packages.mindustry.world.producers)
importPackage(Packages.arc.graphics.g2d)
importPackage(Packages.mindustry.maps.planet)
const PlayerIpUnbanEvent = Packages.mindustry.game.EventType.PlayerIpUnbanEvent const PlayerIpUnbanEvent = Packages.mindustry.game.EventType.PlayerIpUnbanEvent
const PlayerIpBanEvent = Packages.mindustry.game.EventType.PlayerIpBanEvent const PlayerIpBanEvent = Packages.mindustry.game.EventType.PlayerIpBanEvent
const PlayerUnbanEvent = Packages.mindustry.game.EventType.PlayerUnbanEvent const PlayerUnbanEvent = Packages.mindustry.game.EventType.PlayerUnbanEvent
@@ -95,8 +97,7 @@ const PlayerBanEvent = Packages.mindustry.game.EventType.PlayerBanEvent
const PlayerLeave = Packages.mindustry.game.EventType.PlayerLeave const PlayerLeave = Packages.mindustry.game.EventType.PlayerLeave
const PlayerConnect = Packages.mindustry.game.EventType.PlayerConnect const PlayerConnect = Packages.mindustry.game.EventType.PlayerConnect
const PlayerJoin = Packages.mindustry.game.EventType.PlayerJoin const PlayerJoin = Packages.mindustry.game.EventType.PlayerJoin
const MechChangeEvent = Packages.mindustry.game.EventType.MechChangeEvent const UnitChangeEvent = Packages.mindustry.game.EventType.UnitChangeEvent
const ResizeEvent = Packages.mindustry.game.EventType.ResizeEvent
const UnitCreateEvent = Packages.mindustry.game.EventType.UnitCreateEvent const UnitCreateEvent = Packages.mindustry.game.EventType.UnitCreateEvent
const UnitDestroyEvent = Packages.mindustry.game.EventType.UnitDestroyEvent const UnitDestroyEvent = Packages.mindustry.game.EventType.UnitDestroyEvent
const BlockDestroyEvent = Packages.mindustry.game.EventType.BlockDestroyEvent const BlockDestroyEvent = Packages.mindustry.game.EventType.BlockDestroyEvent
@@ -107,12 +108,19 @@ const ResearchEvent = Packages.mindustry.game.EventType.ResearchEvent
const UnlockEvent = Packages.mindustry.game.EventType.UnlockEvent const UnlockEvent = Packages.mindustry.game.EventType.UnlockEvent
const StateChangeEvent = Packages.mindustry.game.EventType.StateChangeEvent const StateChangeEvent = Packages.mindustry.game.EventType.StateChangeEvent
const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent
const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent
const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent
const TapConfigEvent = Packages.mindustry.game.EventType.TapConfigEvent const TapConfigEvent = Packages.mindustry.game.EventType.TapConfigEvent
const TapEvent = Packages.mindustry.game.EventType.TapEvent const TapEvent = Packages.mindustry.game.EventType.TapEvent
const DepositEvent = Packages.mindustry.game.EventType.DepositEvent const DepositEvent = Packages.mindustry.game.EventType.DepositEvent
const WithdrawEvent = Packages.mindustry.game.EventType.WithdrawEvent const WithdrawEvent = Packages.mindustry.game.EventType.WithdrawEvent
const SectorCaptureEvent = Packages.mindustry.game.EventType.SectorCaptureEvent
const ZoneConfigureCompleteEvent = Packages.mindustry.game.EventType.ZoneConfigureCompleteEvent
const ZoneRequireCompleteEvent = Packages.mindustry.game.EventType.ZoneRequireCompleteEvent
const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent
const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent
const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent
const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent
const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent
const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent
const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent
const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent
@@ -123,17 +131,13 @@ const PlayEvent = Packages.mindustry.game.EventType.PlayEvent
const DisposeEvent = Packages.mindustry.game.EventType.DisposeEvent const DisposeEvent = Packages.mindustry.game.EventType.DisposeEvent
const ContentReloadEvent = Packages.mindustry.game.EventType.ContentReloadEvent const ContentReloadEvent = Packages.mindustry.game.EventType.ContentReloadEvent
const ServerLoadEvent = Packages.mindustry.game.EventType.ServerLoadEvent const ServerLoadEvent = Packages.mindustry.game.EventType.ServerLoadEvent
const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent
const ClientCreateEvent = Packages.mindustry.game.EventType.ClientCreateEvent const ClientCreateEvent = Packages.mindustry.game.EventType.ClientCreateEvent
const SaveLoadEvent = Packages.mindustry.game.EventType.SaveLoadEvent const SaveLoadEvent = Packages.mindustry.game.EventType.SaveLoadEvent
const ZoneConfigureCompleteEvent = Packages.mindustry.game.EventType.ZoneConfigureCompleteEvent
const ZoneRequireCompleteEvent = Packages.mindustry.game.EventType.ZoneRequireCompleteEvent
const PlayerChatEvent = Packages.mindustry.game.EventType.PlayerChatEvent
const CommandIssueEvent = Packages.mindustry.game.EventType.CommandIssueEvent
const MapPublishEvent = Packages.mindustry.game.EventType.MapPublishEvent const MapPublishEvent = Packages.mindustry.game.EventType.MapPublishEvent
const MapMakeEvent = Packages.mindustry.game.EventType.MapMakeEvent const MapMakeEvent = Packages.mindustry.game.EventType.MapMakeEvent
const LaunchItemEvent = Packages.mindustry.game.EventType.LaunchItemEvent const ResizeEvent = Packages.mindustry.game.EventType.ResizeEvent
const LaunchEvent = Packages.mindustry.game.EventType.LaunchEvent const LaunchEvent = Packages.mindustry.game.EventType.LaunchEvent
const LoseEvent = Packages.mindustry.game.EventType.LoseEvent const LoseEvent = Packages.mindustry.game.EventType.LoseEvent
const WinEvent = Packages.mindustry.game.EventType.WinEvent const WinEvent = Packages.mindustry.game.EventType.WinEvent
const TurnEvent = Packages.mindustry.game.EventType.TurnEvent
const Trigger = Packages.mindustry.game.EventType.Trigger const Trigger = Packages.mindustry.game.EventType.Trigger

View File

@@ -14,6 +14,7 @@ import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.blocks.campaign.LaunchPad;
import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.defense.turrets.*; import mindustry.world.blocks.defense.turrets.*;
import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.distribution.*;
@@ -1315,7 +1316,7 @@ public class Blocks implements ContentList{
speed = 7f; speed = 7f;
}}; }};
launchPad = new LaunchPad("launch-pad"){{ launchPad = new mindustry.world.blocks.campaign.LaunchPad("launch-pad"){{
requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150)); requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 350, Items.silicon, 140, Items.lead, 200, Items.titanium, 150));
size = 3; size = 3;
itemCapacity = 100; itemCapacity = 100;

View File

@@ -23,6 +23,8 @@ public class GameState{
public Rules rules = new Rules(); public Rules rules = new Rules();
/** Statistics for this save/game. Displayed after game over. */ /** Statistics for this save/game. Displayed after game over. */
public Stats stats = new Stats(); public Stats stats = new Stats();
/** Sector information. Only valid in the campaign. */
public SectorInfo secinfo = new SectorInfo();
/** Team data. Gets reset every new game. */ /** Team data. Gets reset every new game. */
public Teams teams = new Teams(); public Teams teams = new Teams();
/** Number of enemies in the game; only used clientside in servers. */ /** Number of enemies in the game; only used clientside in servers. */

View File

@@ -90,7 +90,7 @@ public class Logic implements ApplicationListener{
} }
}); });
Events.on(LaunchItemEvent.class, e -> state.stats.handleItemExport(e.stack)); Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack));
//when loading a 'damaged' sector, propagate the damage //when loading a 'damaged' sector, propagate the damage
Events.on(WorldLoadEvent.class, e -> { Events.on(WorldLoadEvent.class, e -> {
@@ -100,13 +100,14 @@ public class Logic implements ApplicationListener{
} }
}); });
//TODO this should be in the same place as launch handling code //TODO dying takes up a turn (?)
/*
Events.on(GameOverEvent.class, e -> { Events.on(GameOverEvent.class, e -> {
//simulate a turn on a normal non-launch gameover //simulate a turn on a normal non-launch gameover
if(state.isCampaign() && !state.launched){ if(state.isCampaign() && !state.launched){
universe.runTurn(); universe.runTurn();
} }
}); });*/
//disable new waves after the boss spawns //disable new waves after the boss spawns
Events.on(WaveEvent.class, e -> { Events.on(WaveEvent.class, e -> {
@@ -269,11 +270,9 @@ public class Logic implements ApplicationListener{
//save over the data w/o the cores //save over the data w/o the cores
sector.save.save(); sector.save.save();
//TODO mark sector as not containing any cores
//run a turn, since launching takes up a turn //run a turn, since launching takes up a turn
universe.runTurn(); universe.runTurn();
//TODO needs extra damage to prevent player from landing immediately afterwards
sector.setTurnsPassed(sector.getTurnsPassed() + 3); sector.setTurnsPassed(sector.getTurnsPassed() + 3);
Events.fire(new LaunchEvent()); Events.fire(new LaunchEvent());
@@ -300,7 +299,7 @@ public class Logic implements ApplicationListener{
} }
if(!state.isPaused()){ if(!state.isPaused()){
state.stats.update(); state.secinfo.update();
if(state.isCampaign()){ if(state.isCampaign()){
universe.update(); universe.update();

View File

@@ -188,6 +188,12 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
} }
} }
/** Called clientside when the client taps a block to config.
* @return whether the configuration UI should be shown. */
public boolean configTapped(){
return true;
}
public void applyBoost(float intensity, float duration){ public void applyBoost(float intensity, float duration){
timeScale = Math.max(timeScale, intensity); timeScale = Math.max(timeScale, intensity);
timeScaleDuration = Math.max(timeScaleDuration, duration); timeScaleDuration = Math.max(timeScaleDuration, duration);

View File

@@ -242,10 +242,6 @@ public class Saves{
return isSector(); return isSector();
} }
public ObjectFloatMap<Item> getProductionRates(){
return meta.exportRates;
}
public String getPlayTime(){ public String getPlayTime(){
return Strings.formatMillis(current == this ? totalPlaytime : meta.timePlayed); return Strings.formatMillis(current == this ? totalPlaytime : meta.timePlayed);
} }

View File

@@ -0,0 +1,124 @@
package mindustry.game;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.storage.CoreBlock.*;
import mindustry.world.modules.*;
import static mindustry.Vars.*;
public class SectorInfo{
/** export window size in seconds */
private static final int exportWindow = 60;
/** refresh period of export in ticks */
private static final float refreshPeriod = 60;
/** Export statistics. */
public ObjectMap<Item, ExportStat> export = new ObjectMap<>();
/** Items stored in all cores. */
public ObjectIntMap<Item> coreItems = new ObjectIntMap<>();
/** The best available core type. */
public Block bestCoreType = Blocks.air;
/** Max storage capacity. */
public int storageCapacity = 0;
/** Whether a core is available here. */
public boolean hasCore = true;
/** Counter refresh state. */
private transient Interval time = new Interval();
/** Core item storage to prevent spoofing. */
private transient int[] lastCoreItems;
/** Updates export statistics. */
public void handleItemExport(ItemStack stack){
handleItemExport(stack.item, stack.amount);
}
/** Updates export statistics. */
public void handleItemExport(Item item, int amount){
export.get(item, ExportStat::new).counter += amount;
}
/** Subtracts from export statistics. */
public void handleItemImport(Item item, int amount){
export.get(item, ExportStat::new).counter -= amount;
}
public float getExport(Item item){
return export.get(item, ExportStat::new).mean;
}
/** Prepare data for writing to a save. */
public void prepare(){
//update core items
coreItems.clear();
CoreEntity entity = state.rules.defaultTeam.core();
if(entity != null){
ItemModule items = entity.items;
for(int i = 0; i < items.length(); i++){
coreItems.put(content.item(i), items.get(i));
}
}
hasCore = entity != null;
bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block;
storageCapacity = entity != null ? entity.storageCapacity : 0;
}
/** Update averages of various stats. */
public void update(){
//create last stored core items
if(lastCoreItems == null){
lastCoreItems = new int[content.items().size];
updateCoreDeltas();
}
//refresh throughput
if(time.get(refreshPeriod)){
CoreEntity ent = state.rules.defaultTeam.core();
export.each((item, stat) -> {
//initialize stat after loading
if(!stat.loaded){
stat.means.fill(stat.mean);
stat.loaded = true;
}
//how the resources changed - only interested in negative deltas, since that's what happens during spoofing
int coreDelta = Math.min(ent == null ? 0 : ent.items.get(item) - lastCoreItems[item.id], 0);
//add counter, subtract how many items were taken from the core during this time
stat.means.add(Math.max(stat.counter + coreDelta, 0));
stat.counter = 0;
stat.mean = stat.means.rawMean();
});
updateCoreDeltas();
}
}
private void updateCoreDeltas(){
CoreEntity ent = state.rules.defaultTeam.core();
for(int i = 0; i < lastCoreItems.length; i++){
lastCoreItems[i] = ent == null ? 0 : ent.items.get(i);
}
}
public ObjectFloatMap<Item> exportRates(){
ObjectFloatMap<Item> map = new ObjectFloatMap<>();
export.each((item, value) -> map.put(item, value.mean));
return map;
}
public static class ExportStat{
public transient float counter;
public transient WindowedMean means = new WindowedMean(exportWindow);
public transient boolean loaded;
public float mean;
}
}

View File

@@ -2,21 +2,11 @@ package mindustry.game;
import arc.math.*; import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.blocks.storage.CoreBlock.*;
import mindustry.world.modules.*;
import static mindustry.Vars.*;
//TODO more stats: //TODO more stats:
//- units constructed //- units constructed
public class Stats{ public class Stats{
/** export window size in seconds */
private static final int exportWindow = 60;
/** refresh period of export in ticks */
private static final float refreshPeriod = 60;
/** Total items delivered to global resoure counter. Campaign only. */ /** Total items delivered to global resoure counter. Campaign only. */
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>(); public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
/** Enemy (red team) units destroyed. */ /** Enemy (red team) units destroyed. */
@@ -31,89 +21,6 @@ public class Stats{
public int buildingsDeconstructed; public int buildingsDeconstructed;
/** Friendly buildings destroyed. */ /** Friendly buildings destroyed. */
public int buildingsDestroyed; public int buildingsDestroyed;
/** Export statistics. */
public ObjectMap<Item, ExportStat> export = new ObjectMap<>();
/** Items stored in all cores. Used for the campaign. */
public ObjectIntMap<Item> coreItems = new ObjectIntMap<>();
/** Counter refresh state. */
private transient Interval time = new Interval();
/** Core item storage to prevent spoofing. */
private transient int[] lastCoreItems;
/** Updates export statistics. */
public void handleItemExport(ItemStack stack){
handleItemExport(stack.item, stack.amount);
}
/** Updates export statistics. */
public void handleItemExport(Item item, int amount){
export.get(item, ExportStat::new).counter += amount;
}
/** Subtracts from export statistics. */
public void handleItemImport(Item item, int amount){
export.get(item, ExportStat::new).counter -= amount;
}
public float getExport(Item item){
return export.get(item, ExportStat::new).mean;
}
public void update(){
//update core items
CoreEntity entity = state.rules.defaultTeam.core();
if(entity != null){
ItemModule items = entity.items;
for(int i = 0; i < items.length(); i++){
coreItems.put(content.item(i), items.get(i));
}
}else{
coreItems.clear();
}
//create last stored core items
if(lastCoreItems == null){
lastCoreItems = new int[content.items().size];
updateCoreDeltas();
}
//refresh throughput
if(time.get(refreshPeriod)){
CoreEntity ent = state.rules.defaultTeam.core();
export.each((item, stat) -> {
//initialize stat after loading
if(!stat.loaded){
stat.means.fill(stat.mean);
stat.loaded = true;
}
//how the resources changed - only interested in negative deltas, since that's what happens during spoofing
int coreDelta = Math.min(ent == null ? 0 : ent.items.get(item) - lastCoreItems[item.id], 0);
//add counter, subtract how many items were taken from the core during this time
stat.means.add(Math.max(stat.counter + coreDelta, 0));
stat.counter = 0;
stat.mean = stat.means.rawMean();
});
updateCoreDeltas();
}
}
private void updateCoreDeltas(){
CoreEntity ent = state.rules.defaultTeam.core();
for(int i = 0; i < lastCoreItems.length; i++){
lastCoreItems[i] = ent == null ? 0 : ent.items.get(i);
}
}
public ObjectFloatMap<Item> exportRates(){
ObjectFloatMap<Item> map = new ObjectFloatMap<>();
export.each((item, value) -> map.put(item, value.mean));
return map;
}
public RankResult calculateRank(Sector zone, boolean launched){ public RankResult calculateRank(Sector zone, boolean launched){
float score = 0; float score = 0;
@@ -161,15 +68,7 @@ public class Stats{
} }
} }
public enum Rank{ public enum Rank{
F, D, C, B, A, S, SS F, D, C, B, A, S, SS
} }
public static class ExportStat{
public transient float counter;
public transient WindowedMean means = new WindowedMean(exportWindow);
public transient boolean loaded;
public float mean;
}
} }

View File

@@ -3,7 +3,6 @@ package mindustry.io;
import arc.struct.*; import arc.struct.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.maps.*; import mindustry.maps.*;
import mindustry.type.*;
import static mindustry.Vars.maps; import static mindustry.Vars.maps;
@@ -15,13 +14,12 @@ public class SaveMeta{
public Map map; public Map map;
public int wave; public int wave;
public Rules rules; public Rules rules;
public SectorInfo secinfo;
public StringMap tags; public StringMap tags;
public String[] mods; public String[] mods;
/** These are in items/second. */
public ObjectFloatMap<Item> exportRates;
public boolean hasProduction; public boolean hasProduction;
public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, ObjectFloatMap<Item> exportRates, StringMap tags){ public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, SectorInfo secinfo, StringMap tags){
this.version = version; this.version = version;
this.build = build; this.build = build;
this.timestamp = timestamp; this.timestamp = timestamp;
@@ -31,8 +29,8 @@ public class SaveMeta{
this.rules = rules; this.rules = rules;
this.tags = tags; this.tags = tags;
this.mods = JsonIO.read(String[].class, tags.get("mods", "[]")); this.mods = JsonIO.read(String[].class, tags.get("mods", "[]"));
this.exportRates = exportRates; this.secinfo = secinfo;
exportRates.each(e -> hasProduction |= e.value > 0.001f); secinfo.exportRates().each(e -> hasProduction |= e.value > 0.001f);
} }
} }

View File

@@ -39,7 +39,7 @@ public abstract class SaveVersion extends SaveFileReader{
map.get("mapname"), map.get("mapname"),
map.getInt("wave"), map.getInt("wave"),
JsonIO.read(Rules.class, map.get("rules", "{}")), JsonIO.read(Rules.class, map.get("rules", "{}")),
JsonIO.read(Stats.class, map.get("stats", "{}")).exportRates(), JsonIO.read(SectorInfo.class, map.get("secinfo", "{}")),
map map
); );
} }
@@ -70,6 +70,11 @@ public abstract class SaveVersion extends SaveFileReader{
} }
public void writeMeta(DataOutput stream, StringMap tags) throws IOException{ public void writeMeta(DataOutput stream, StringMap tags) throws IOException{
//prepare campaign data for writing
if(state.isCampaign()){
state.secinfo.prepare();
}
writeStringMap(stream, StringMap.of( writeStringMap(stream, StringMap.of(
"saved", Time.millis(), "saved", Time.millis(),
"playtime", headless ? 0 : control.saves.getTotalPlaytime(), "playtime", headless ? 0 : control.saves.getTotalPlaytime(),
@@ -78,6 +83,7 @@ public abstract class SaveVersion extends SaveFileReader{
"wave", state.wave, "wave", state.wave,
"wavetime", state.wavetime, "wavetime", state.wavetime,
"stats", JsonIO.write(state.stats), "stats", JsonIO.write(state.stats),
"secinfo", state.isCampaign() ? JsonIO.write(state.secinfo) : "{}",
"rules", JsonIO.write(state.rules), "rules", JsonIO.write(state.rules),
"mods", JsonIO.write(mods.getModStrings().toArray(String.class)), "mods", JsonIO.write(mods.getModStrings().toArray(String.class)),
"width", world.width(), "width", world.width(),
@@ -94,6 +100,7 @@ public abstract class SaveVersion extends SaveFileReader{
state.wave = map.getInt("wave"); state.wave = map.getInt("wave");
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing); state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
state.stats = JsonIO.read(Stats.class, map.get("stats", "{}")); state.stats = JsonIO.read(Stats.class, map.get("stats", "{}"));
state.secinfo = JsonIO.read(SectorInfo.class, map.get("secinfo", "{}"));
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
lastReadBuild = map.getInt("build", -1); lastReadBuild = map.getInt("build", -1);

View File

@@ -17,6 +17,7 @@ import java.net.*;
import java.util.regex.*; import java.util.regex.*;
public class Scripts implements Disposable{ public class Scripts implements Disposable{
private final static Object[] emptyObjects = {};
private final Array<String> blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk", private final Array<String> blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk",
"runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system", "runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system",
".awt", "socket", "classloader", "oracle", "invoke", "arc.events", "java.util.function", "java.util.stream"); ".awt", "socket", "classloader", "oracle", "invoke", "arc.events", "java.util.function", "java.util.stream");

View File

@@ -9,6 +9,7 @@ import arc.input.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.scene.event.*; import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.TextButton.*; import arc.scene.ui.TextButton.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
@@ -152,6 +153,17 @@ public class PlanetDialog extends BaseDialog{
shown(this::setup); shown(this::setup);
} }
/** show with no limitations, just as a map. */
@Override
public Dialog show(){
//TODO
return super.show();
}
public void show(Sector selected, int range){
//TODO
}
void makeBloom(){ void makeBloom(){
if(bloom != null){ if(bloom != null){
bloom.dispose(); bloom.dispose();
@@ -413,7 +425,7 @@ public class PlanetDialog extends BaseDialog{
stable.table(t -> { stable.table(t -> {
t.left(); t.left();
selected.save.meta.exportRates.each(entry -> { selected.save.meta.secinfo.exportRates().each(entry -> {
int total = (int)(entry.value * turnDuration / 60f); int total = (int)(entry.value * turnDuration / 60f);
if(total > 1){ if(total > 1){
t.image(entry.key.icon(Cicon.small)).padRight(3); t.image(entry.key.icon(Cicon.small)).padRight(3);
@@ -421,7 +433,24 @@ public class PlanetDialog extends BaseDialog{
t.row(); t.row();
} }
}); });
}); }).row();
}
//stored resources
if(selected.hasBase() && selected.save.meta.secinfo.coreItems.size > 0){
stable.add("Stored Resources:").row();
stable.table(t -> {
t.left();
for(Item item : content.items()){
int amount = selected.save.meta.secinfo.coreItems.get(item);
if(amount > 0){
t.image(item.icon(Cicon.small)).padRight(3);
t.add(ui.formatAmount(amount)).color(Color.lightGray);
t.row();
}
}
}).row();
} }
//display how many turns this sector has been attacked //display how many turns this sector has been attacked

View File

@@ -43,29 +43,31 @@ public class BlockConfigFragment extends Fragment{
} }
public void showConfig(Tilec tile){ public void showConfig(Tilec tile){
configTile = tile; if(tile.configTapped()){
configTile = tile;
table.visible(true); table.visible(true);
table.clear(); table.clear();
tile.buildConfiguration(table); tile.buildConfiguration(table);
table.pack(); table.pack();
table.setTransform(true); table.setTransform(true);
table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true),
Actions.scaleTo(1f, 1f, 0.07f, Interp.pow3Out)); Actions.scaleTo(1f, 1f, 0.07f, Interp.pow3Out));
table.update(() -> { table.update(() -> {
if(configTile != null && configTile.shouldHideConfigure(player)){ if(configTile != null && configTile.shouldHideConfigure(player)){
hideConfig(); hideConfig();
return; return;
} }
table.setOrigin(Align.center); table.setOrigin(Align.center);
if(configTile == null || configTile.block() == Blocks.air || !configTile.isValid()){ if(configTile == null || configTile.block() == Blocks.air || !configTile.isValid()){
hideConfig(); hideConfig();
}else{ }else{
configTile.updateTableAlign(table); configTile.updateTableAlign(table);
} }
}); });
}
} }
public boolean hasConfigMouse(){ public boolean hasConfigMouse(){

View File

@@ -326,9 +326,9 @@ public class HudFragment extends Fragment{
c.clearChildren(); c.clearChildren();
for(Item item : content.items()){ for(Item item : content.items()){
if(state.stats.getExport(item) >= 1){ if(state.secinfo.getExport(item) >= 1){
c.image(item.icon(Cicon.small)); c.image(item.icon(Cicon.small));
c.label(() -> (int)state.stats.getExport(item) + " /s").color(Color.lightGray); c.label(() -> (int)state.secinfo.getExport(item) + " /s").color(Color.lightGray);
c.row(); c.row();
} }
} }
@@ -337,7 +337,7 @@ public class HudFragment extends Fragment{
c.update(() -> { c.update(() -> {
boolean wrong = false; boolean wrong = false;
for(Item item : content.items()){ for(Item item : content.items()){
boolean has = state.stats.getExport(item) >= 1; boolean has = state.secinfo.getExport(item) >= 1;
if(used.get(item.id) != has){ if(used.get(item.id) != has){
used.set(item.id, has); used.set(item.id, has);
wrong = true; wrong = true;

View File

@@ -0,0 +1,33 @@
package mindustry.world.blocks.campaign;
import mindustry.*;
import mindustry.gen.*;
import mindustry.world.*;
public class CoreLauncher extends Block{
public CoreLauncher(String name){
super(name);
hasItems = true;
configurable = true;
}
public class CoreLauncherEntity extends TileEntity{
@Override
public void updateTile(){
super.updateTile();
}
@Override
public boolean configTapped(){
//TODO show w/ sector
Vars.ui.planet.show();
return false;
}
}
}

View File

@@ -1,4 +1,4 @@
package mindustry.world.blocks.storage; package mindustry.world.blocks.campaign;
import arc.*; import arc.*;
import arc.graphics.*; import arc.graphics.*;

View File

@@ -1,4 +1,4 @@
package mindustry.world.blocks.production; package mindustry.world.blocks.campaign;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;