Merging changes from private branch

This commit is contained in:
Anuken
2025-04-04 11:47:35 -04:00
parent cf5c6d0905
commit b7dbe54d76
161 changed files with 2484 additions and 1137 deletions

View File

@@ -9,6 +9,7 @@ import mindustry.net.*;
import mindustry.net.Packets.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.storage.CoreBlock.*;
public class EventType{
@@ -82,6 +83,8 @@ public class EventType{
public static class BlockInfoEvent{}
/** Called *after* all content has been initialized. */
public static class ContentInitEvent{}
/** Called *after* all content has been added to the atlas, but before its pixmaps are disposed. */
public static class AtlasPackEvent{}
/** Called *after* all mod content has been loaded, but before it has been initialized. */
public static class ModContentLoadEvent{}
/** Called when the client game is first loaded. */
@@ -395,6 +398,22 @@ public class EventType{
}
}
/**
* Called when a tile changes its floor. Do not cache or use with a timer.
* Do not modify any tiles inside listener code.
* */
public static class TileFloorChangeEvent{
public Tile tile;
public Floor previous, floor;
public TileFloorChangeEvent set(Tile tile, Floor previous, Floor floor){
this.tile = tile;
this.previous = previous;
this.floor = floor;
return this;
}
}
/**
* Called after a building's team changes.
* Event object is reused, do not nest!

View File

@@ -36,6 +36,7 @@ public final class FogControl implements CustomChunk{
private boolean justLoaded = false;
private boolean loadedStatic = false;
private int lastEntityUpdateIndex = 0;
public FogControl(){
Events.on(ResetEvent.class, e -> {
@@ -131,6 +132,7 @@ public final class FogControl implements CustomChunk{
}
void stop(){
lastEntityUpdateIndex = 0;
fog = null;
//I don't care whether the fog thread crashes here, it's about to die anyway
staticEvents.clear();
@@ -214,6 +216,31 @@ public final class FogControl implements CustomChunk{
//clear to prepare for queuing fog radius from units and buildings
dynamicEventQueue.clear();
//update fog visibility manually
if(state.rules.fog && !headless && Groups.build.size() > 0){
int size = Groups.build.size();
int chunkSize = 5; //fraction of entity list to iterate each frame
int chunks = Math.min(chunkSize, size);
int iterated = Math.max(1, size / chunks);
int steps = 0;
int i = lastEntityUpdateIndex % size;
while(steps < iterated){
Groups.build.index(i).updateFogVisibility();
steps ++;
i ++;
if(i >= size){
i = 0;
}
}
lastEntityUpdateIndex = i;
}
for(var team : state.teams.present){
//AI teams do not have fog
if(!team.team.isOnlyAI()){

View File

@@ -277,6 +277,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
String className = getClass().getSimpleName().replace("Objective", "");
return Core.bundle == null ? className : Core.bundle.get("objective." + className.toLowerCase() + ".name", className);
}
/** Validate fields after reading to make sure none of them are null. */
public void validate(){
}
}
/** Research a specific piece of content in the tech tree. */
@@ -298,6 +303,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.research", content.emoji(), content.localizedName);
}
@Override
public void validate(){
if(content == null) content = Items.copper;
}
}
/** Produce a specific piece of content in the tech tree (essentially research with different text). */
@@ -319,6 +329,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.produce", content.emoji(), content.localizedName);
}
@Override
public void validate(){
if(content == null) content = Items.copper;
}
}
/** Have a certain amount of item in your core. */
@@ -342,6 +357,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.item", state.rules.defaultTeam.items().get(item), amount, item.emoji(), item.localizedName);
}
@Override
public void validate(){
if(item == null) item = Items.copper;
}
}
/** Get a certain item in your core (through a block, not manually.) */
@@ -365,6 +385,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.coreitem", state.stats.coreItemCount.get(item), amount, item.emoji(), item.localizedName);
}
@Override
public void validate(){
if(item == null) item = Items.copper;
}
}
/** Build a certain amount of a block. */
@@ -388,6 +413,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.build", count - state.stats.placedBlockCount.get(block, 0), block.emoji(), block.localizedName);
}
@Override
public void validate(){
if(block == null) block = Blocks.conveyor;
}
}
/** Produce a certain amount of a unit. */
@@ -411,6 +441,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.buildunit", count - state.rules.defaultTeam.data().countType(unit), unit.emoji(), unit.localizedName);
}
@Override
public void validate(){
if(unit == null) unit = UnitTypes.dagger;
}
}
/** Produce a certain amount of units. */
@@ -524,6 +559,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.destroyblock", block.emoji(), block.localizedName);
}
@Override
public void validate(){
if(block == null) block = Blocks.router;
}
}
public static class DestroyBlocksObjective extends MapObjective{
@@ -559,6 +599,11 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
public String text(){
return Core.bundle.format("objective.destroyblocks", progress(), positions.length, block.emoji(), block.localizedName);
}
@Override
public void validate(){
if(block == null) block = Blocks.router;
}
}
/** Command any unit to do anything. Always compete in headless mode. */

View File

@@ -1,11 +1,11 @@
package mindustry.game;
import arc.func.*;
import arc.struct.*;
import arc.util.*;
import arc.util.serialization.*;
import arc.util.serialization.Json.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.gen.*;
import mindustry.io.versions.*;
import mindustry.type.*;
@@ -48,6 +48,8 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
public @Nullable StatusEffect effect;
/** Items this unit spawns with. Null to disable. */
public @Nullable ItemStack items;
/** Team that units spawned use. Null for default wave team. */
public @Nullable Team team;
public SpawnGroup(UnitType type){
this.type = type;
@@ -75,12 +77,9 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
return Math.max(shields + shieldScaling*(wave - begin), 0);
}
/**
* Creates a unit, and assigns correct values based on this group's data.
* This method does not add() the unit.
*/
public Unit createUnit(Team team, int wave){
Unit unit = type.create(team);
/** Creates a unit, and assigns correct values based on this group's data. */
public Unit createUnit(Team team, float x, float y, float rotation, int wave, Cons<Unit> cons){
Unit unit = type.spawn(team, x, y, rotation, cons);
if(effect != null){
unit.apply(effect, 999999f);
@@ -104,6 +103,11 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
return unit;
}
/** Creates a unit, and assigns correct values based on this group's data. */
public Unit createUnit(Team team, int wave){
return createUnit(team, 0f, 0f, 0f, wave, u -> {});
}
@Override
public void write(Json json){
if(type == null) type = UnitTypes.dagger;
@@ -120,7 +124,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
if(spawn != -1) json.writeValue("spawn", spawn);
if(payloads != null && payloads.any()) json.writeValue("payloads", payloads.map(u -> u.name).toArray(String.class));
if(items != null && items.amount > 0) json.writeValue("items", items);
if(team != null) json.writeValue("team", team.id);
}
@Override
@@ -140,6 +144,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{
spawn = data.getInt("spawn", -1);
if(data.has("payloads")) payloads = Seq.with(json.readValue(String[].class, data.get("payloads"))).map(content::unit).removeAll(t -> t == null);
if(data.has("items")) items = json.readValue(ItemStack.class, data.get("items"));
if(data.has("team")) team = Team.get(data.getInt("team"));
//old boss effect ID

View File

@@ -19,6 +19,7 @@ public class Team implements Comparable<Team>, Senseable{
public final Color color = new Color();
public final Color[] palette = {new Color(), new Color(), new Color()};
public final int[] palettei = new int[3];
public boolean ignoreUnitCap = false;
public String emoji = "";
public boolean hasPalette;
public String name;
@@ -50,6 +51,8 @@ public class Team implements Comparable<Team>, Senseable{
new Team(i, "team#" + i, Color.HSVtoRGB(360f * Mathf.random(), 100f * Mathf.random(0.4f, 1f), 100f * Mathf.random(0.6f, 1f), 1f));
}
Mathf.rand.setSeed(new Rand().nextLong());
neoplastic.ignoreUnitCap = true;
}
public static Team get(int id){
@@ -95,10 +98,16 @@ public class Team implements Comparable<Team>, Senseable{
return data().core();
}
/** @return whether this team has any buildings on this map; in waves mode, this is always true for the enemy team. */
public boolean active(){
return state.teams.isActive(this);
}
/** @return whether this team has any active cores. Not the same as active()! */
public boolean isAlive(){
return data().isAlive();
}
/** @return whether this team is supposed to be AI-controlled. */
public boolean isAI(){
return (state.rules.waves || state.rules.attackMode) && this != state.rules.defaultTeam && !state.rules.pvp;
@@ -114,12 +123,6 @@ public class Team implements Comparable<Team>, Senseable{
return isAI() && !rules().rtsAi;
}
/** @deprecated There is absolutely no reason to use this. */
@Deprecated
public boolean isEnemy(Team other){
return this != other;
}
public Seq<CoreBuild> cores(){
return state.teams.cores(this);
}
@@ -161,6 +164,7 @@ public class Team implements Comparable<Team>, Senseable{
@Override
public double sense(LAccess sensor){
if(sensor == LAccess.id) return id;
return 0;
if(sensor == LAccess.color) return color.toDoubleBits();
return Double.NaN;
}
}

View File

@@ -126,6 +126,15 @@ public class Teams{
return active;
}
public void updateActive(Team team){
TeamData data = get(team);
//register in active list if needed
if(data.active() && !active.contains(data)){
active.add(data);
updateEnemies();
}
}
public void registerCore(CoreBuild core){
TeamData data = get(core.team);
//add core if not present
@@ -407,13 +416,18 @@ public class Teams{
}
public boolean active(){
return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0;
return (team == state.rules.waveTeam && state.rules.waves) || cores.size > 0 || buildings.size > 0 || (team == Team.neoplastic && units.size > 0);
}
public boolean hasCore(){
return cores.size > 0;
}
/** @return whether this team has any cores (standard team), or any hearts (neoplasm). */
public boolean isAlive(){
return hasCore();
}
public boolean noCores(){
return cores.isEmpty();
}