diff --git a/build.gradle b/build.gradle index b6a78b673..b950ef535 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,7 @@ dependencies { implementation "com.simsilica:zay-es-net:1.4.2" implementation "com.simsilica:sio2:1.3.0" implementation "com.simsilica:sim-ethereal:1.5.0" + implementation "org.reflections:reflections:0.9.11" } sourceSets { diff --git a/src/toniarts/openkeeper/game/component/AttackTarget.java b/src/toniarts/openkeeper/game/component/AttackTarget.java index b1c32abf5..fa86f9b70 100644 --- a/src/toniarts/openkeeper/game/component/AttackTarget.java +++ b/src/toniarts/openkeeper/game/component/AttackTarget.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import com.simsilica.es.EntityId; +import toniarts.openkeeper.game.network.Transferable; /** * Marks that entity is attacking a target * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class AttackTarget implements EntityComponent { public EntityId entityId; diff --git a/src/toniarts/openkeeper/game/component/ChickenAi.java b/src/toniarts/openkeeper/game/component/ChickenAi.java index 5a01c1e8d..85f7adb36 100644 --- a/src/toniarts/openkeeper/game/component/ChickenAi.java +++ b/src/toniarts/openkeeper/game/component/ChickenAi.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import toniarts.openkeeper.game.controller.chicken.ChickenState; +import toniarts.openkeeper.game.network.Transferable; /** * Simple chicken AI component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ChickenAi implements EntityComponent { public double stateStartTime; diff --git a/src/toniarts/openkeeper/game/component/ChickenGenerator.java b/src/toniarts/openkeeper/game/component/ChickenGenerator.java index 9f3ddf692..7d39d5367 100644 --- a/src/toniarts/openkeeper/game/component/ChickenGenerator.java +++ b/src/toniarts/openkeeper/game/component/ChickenGenerator.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Just a tagging component for chicken generators * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ChickenGenerator implements EntityComponent { public ChickenGenerator() { diff --git a/src/toniarts/openkeeper/game/component/CreatureAi.java b/src/toniarts/openkeeper/game/component/CreatureAi.java index 55abf60a0..bdd0c3040 100644 --- a/src/toniarts/openkeeper/game/component/CreatureAi.java +++ b/src/toniarts/openkeeper/game/component/CreatureAi.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import toniarts.openkeeper.game.controller.creature.CreatureState; +import toniarts.openkeeper.game.network.Transferable; /** * Simple creature AI component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureAi implements EntityComponent { public double stateStartTime; diff --git a/src/toniarts/openkeeper/game/component/CreatureComponent.java b/src/toniarts/openkeeper/game/component/CreatureComponent.java index 4890b7b3f..fac624d42 100644 --- a/src/toniarts/openkeeper/game/component/CreatureComponent.java +++ b/src/toniarts/openkeeper/game/component/CreatureComponent.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Simple creature component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureComponent implements EntityComponent { public String name; diff --git a/src/toniarts/openkeeper/game/component/CreatureEfficiency.java b/src/toniarts/openkeeper/game/component/CreatureEfficiency.java index 2e64ed0ac..71e6d18f6 100644 --- a/src/toniarts/openkeeper/game/component/CreatureEfficiency.java +++ b/src/toniarts/openkeeper/game/component/CreatureEfficiency.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Entity efficiency, for working etc. * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureEfficiency implements EntityComponent { public int efficiencyPercentage; diff --git a/src/toniarts/openkeeper/game/component/CreatureExperience.java b/src/toniarts/openkeeper/game/component/CreatureExperience.java index a13dac26e..7a54a44ab 100644 --- a/src/toniarts/openkeeper/game/component/CreatureExperience.java +++ b/src/toniarts/openkeeper/game/component/CreatureExperience.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Creature experience level stuff * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureExperience implements EntityComponent { public int level; diff --git a/src/toniarts/openkeeper/game/component/CreatureFall.java b/src/toniarts/openkeeper/game/component/CreatureFall.java index 50d7a0f36..d5a155486 100644 --- a/src/toniarts/openkeeper/game/component/CreatureFall.java +++ b/src/toniarts/openkeeper/game/component/CreatureFall.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Until the physics handle this etc. This also determines what happens when we @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureFall implements EntityComponent { public CreatureFall() { diff --git a/src/toniarts/openkeeper/game/component/CreatureHunger.java b/src/toniarts/openkeeper/game/component/CreatureHunger.java index 3fa43d33e..854a4c79f 100644 --- a/src/toniarts/openkeeper/game/component/CreatureHunger.java +++ b/src/toniarts/openkeeper/game/component/CreatureHunger.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Creature hunger component. Marks the need for eating overall. * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureHunger implements EntityComponent { public double lastEatTime; diff --git a/src/toniarts/openkeeper/game/component/CreatureImprisoned.java b/src/toniarts/openkeeper/game/component/CreatureImprisoned.java index e18a5c8ef..ff6a1def9 100644 --- a/src/toniarts/openkeeper/game/component/CreatureImprisoned.java +++ b/src/toniarts/openkeeper/game/component/CreatureImprisoned.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags creature as being imprisoned * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureImprisoned implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/CreatureMeleeAttack.java b/src/toniarts/openkeeper/game/component/CreatureMeleeAttack.java index a5c75414a..829adc00c 100644 --- a/src/toniarts/openkeeper/game/component/CreatureMeleeAttack.java +++ b/src/toniarts/openkeeper/game/component/CreatureMeleeAttack.java @@ -16,6 +16,8 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.Creature; /** @@ -23,6 +25,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureMeleeAttack extends Attack { public int attackType; diff --git a/src/toniarts/openkeeper/game/component/CreatureMood.java b/src/toniarts/openkeeper/game/component/CreatureMood.java index 0b9748ca1..561ef34e7 100644 --- a/src/toniarts/openkeeper/game/component/CreatureMood.java +++ b/src/toniarts/openkeeper/game/component/CreatureMood.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Creatures mood... Looking at the evidence I suspect that this is an int value @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureMood implements EntityComponent { public int moodValue; diff --git a/src/toniarts/openkeeper/game/component/CreatureRecuperating.java b/src/toniarts/openkeeper/game/component/CreatureRecuperating.java index a546e9ff5..b00c62a86 100644 --- a/src/toniarts/openkeeper/game/component/CreatureRecuperating.java +++ b/src/toniarts/openkeeper/game/component/CreatureRecuperating.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags creature as recuperating from wounds * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureRecuperating implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/CreatureSleep.java b/src/toniarts/openkeeper/game/component/CreatureSleep.java index 2daee6965..bcbb63c02 100644 --- a/src/toniarts/openkeeper/game/component/CreatureSleep.java +++ b/src/toniarts/openkeeper/game/component/CreatureSleep.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import com.simsilica.es.EntityId; +import toniarts.openkeeper.game.network.Transferable; /** * Creature sleeping component. Marks the need for sleep overall. * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureSleep implements EntityComponent { public EntityId lairObjectId; diff --git a/src/toniarts/openkeeper/game/component/CreatureTortured.java b/src/toniarts/openkeeper/game/component/CreatureTortured.java index 3441685ce..608679016 100644 --- a/src/toniarts/openkeeper/game/component/CreatureTortured.java +++ b/src/toniarts/openkeeper/game/component/CreatureTortured.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags creature is being tortured (not the kinky kind) * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureTortured implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/CreatureViewState.java b/src/toniarts/openkeeper/game/component/CreatureViewState.java index fa17438ec..f292b0f9c 100644 --- a/src/toniarts/openkeeper/game/component/CreatureViewState.java +++ b/src/toniarts/openkeeper/game/component/CreatureViewState.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.Creature.AnimationType; /** @@ -25,6 +27,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class CreatureViewState implements EntityComponent { public short creatureId; diff --git a/src/toniarts/openkeeper/game/component/Death.java b/src/toniarts/openkeeper/game/component/Death.java index 39d4f61be..8cd4c417b 100644 --- a/src/toniarts/openkeeper/game/component/Death.java +++ b/src/toniarts/openkeeper/game/component/Death.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tagging component for something that has been deaded by death. Allows to @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Death implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/Decay.java b/src/toniarts/openkeeper/game/component/Decay.java index d289e4bdd..c7be45845 100644 --- a/src/toniarts/openkeeper/game/component/Decay.java +++ b/src/toniarts/openkeeper/game/component/Decay.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Kinda like a death counter. * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Decay implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/DoorComponent.java b/src/toniarts/openkeeper/game/component/DoorComponent.java index 06817d75d..4797ae476 100644 --- a/src/toniarts/openkeeper/game/component/DoorComponent.java +++ b/src/toniarts/openkeeper/game/component/DoorComponent.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * A base door component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class DoorComponent implements EntityComponent { public short doorId; diff --git a/src/toniarts/openkeeper/game/component/DoorViewState.java b/src/toniarts/openkeeper/game/component/DoorViewState.java index 1d43f2622..d2c004e6a 100644 --- a/src/toniarts/openkeeper/game/component/DoorViewState.java +++ b/src/toniarts/openkeeper/game/component/DoorViewState.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Determines that the entity should be viewed as an door. Visual presentation @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class DoorViewState implements EntityComponent { public short doorId; diff --git a/src/toniarts/openkeeper/game/component/Fearless.java b/src/toniarts/openkeeper/game/component/Fearless.java index 9b8cc6b3e..30c2e7992 100644 --- a/src/toniarts/openkeeper/game/component/Fearless.java +++ b/src/toniarts/openkeeper/game/component/Fearless.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags an entity to be fearless, either by a brief moment in time or by nature * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Fearless implements EntityComponent { public Double startTime; diff --git a/src/toniarts/openkeeper/game/component/FollowTarget.java b/src/toniarts/openkeeper/game/component/FollowTarget.java index dda7c446a..cdb7648a4 100644 --- a/src/toniarts/openkeeper/game/component/FollowTarget.java +++ b/src/toniarts/openkeeper/game/component/FollowTarget.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import com.simsilica.es.EntityId; +import toniarts.openkeeper.game.network.Transferable; /** * Marks that entity is following a target * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class FollowTarget implements EntityComponent { public EntityId entityId; diff --git a/src/toniarts/openkeeper/game/component/Food.java b/src/toniarts/openkeeper/game/component/Food.java index 8535a7d54..79d582496 100644 --- a/src/toniarts/openkeeper/game/component/Food.java +++ b/src/toniarts/openkeeper/game/component/Food.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Just a tagging component for food items * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Food implements EntityComponent { public Food() { diff --git a/src/toniarts/openkeeper/game/component/Gold.java b/src/toniarts/openkeeper/game/component/Gold.java index c343af1ab..b8fb7144b 100644 --- a/src/toniarts/openkeeper/game/component/Gold.java +++ b/src/toniarts/openkeeper/game/component/Gold.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Simple gold container * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Gold implements EntityComponent { public int gold; diff --git a/src/toniarts/openkeeper/game/component/HauledBy.java b/src/toniarts/openkeeper/game/component/HauledBy.java index ba89de521..0699f09f3 100644 --- a/src/toniarts/openkeeper/game/component/HauledBy.java +++ b/src/toniarts/openkeeper/game/component/HauledBy.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import com.simsilica.es.EntityId; +import toniarts.openkeeper.game.network.Transferable; /** * Marks entity to be hauled/dragged by another entity * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class HauledBy implements EntityComponent { public EntityId entityId; diff --git a/src/toniarts/openkeeper/game/component/Health.java b/src/toniarts/openkeeper/game/component/Health.java index a3540c477..ef7e97e63 100644 --- a/src/toniarts/openkeeper/game/component/Health.java +++ b/src/toniarts/openkeeper/game/component/Health.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Simple health component, essentially without this, you are dead * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Health implements EntityComponent { public int ownLandHealthIncrease; diff --git a/src/toniarts/openkeeper/game/component/InHand.java b/src/toniarts/openkeeper/game/component/InHand.java index cd8f1acd5..5899910c0 100644 --- a/src/toniarts/openkeeper/game/component/InHand.java +++ b/src/toniarts/openkeeper/game/component/InHand.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags an entity to be on keeper's hand * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class InHand implements EntityComponent { public int index; diff --git a/src/toniarts/openkeeper/game/component/Interaction.java b/src/toniarts/openkeeper/game/component/Interaction.java index 8e9324779..c92a2d954 100644 --- a/src/toniarts/openkeeper/game/component/Interaction.java +++ b/src/toniarts/openkeeper/game/component/Interaction.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * This entity tells what actions if any are possible for an entity (hmm, not @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Interaction implements EntityComponent { public boolean interactable; diff --git a/src/toniarts/openkeeper/game/component/Mobile.java b/src/toniarts/openkeeper/game/component/Mobile.java index db5cd0e35..73b922d60 100644 --- a/src/toniarts/openkeeper/game/component/Mobile.java +++ b/src/toniarts/openkeeper/game/component/Mobile.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * This signifies that the given entity can roam through the map * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Mobile implements EntityComponent { public boolean canFly; diff --git a/src/toniarts/openkeeper/game/component/Navigation.java b/src/toniarts/openkeeper/game/component/Navigation.java index 1eb6fc042..53aa2872d 100644 --- a/src/toniarts/openkeeper/game/component/Navigation.java +++ b/src/toniarts/openkeeper/game/component/Navigation.java @@ -17,15 +17,18 @@ package toniarts.openkeeper.game.component; import com.badlogic.gdx.math.Vector2; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import java.awt.Point; import java.util.List; +import toniarts.openkeeper.game.network.Transferable; /** * An entity class marking... well.. target of navigation with full path * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Navigation implements EntityComponent { public Point target; diff --git a/src/toniarts/openkeeper/game/component/ObjectComponent.java b/src/toniarts/openkeeper/game/component/ObjectComponent.java index 4a140b6cc..49435b3f0 100644 --- a/src/toniarts/openkeeper/game/component/ObjectComponent.java +++ b/src/toniarts/openkeeper/game/component/ObjectComponent.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * A base object component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ObjectComponent implements EntityComponent { public short objectId; diff --git a/src/toniarts/openkeeper/game/component/ObjectViewState.java b/src/toniarts/openkeeper/game/component/ObjectViewState.java index 2c78a99ac..236ad2728 100644 --- a/src/toniarts/openkeeper/game/component/ObjectViewState.java +++ b/src/toniarts/openkeeper/game/component/ObjectViewState.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.GameObject; /** @@ -25,6 +27,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ObjectViewState implements EntityComponent { public short objectId; diff --git a/src/toniarts/openkeeper/game/component/Objective.java b/src/toniarts/openkeeper/game/component/Objective.java index 95b453f65..9d44706f3 100644 --- a/src/toniarts/openkeeper/game/component/Objective.java +++ b/src/toniarts/openkeeper/game/component/Objective.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.Thing; /** @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Objective implements EntityComponent { public Thing.HeroParty.Objective objective; diff --git a/src/toniarts/openkeeper/game/component/Owner.java b/src/toniarts/openkeeper/game/component/Owner.java index 0e46e814d..1eab54092 100644 --- a/src/toniarts/openkeeper/game/component/Owner.java +++ b/src/toniarts/openkeeper/game/component/Owner.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * An entity class marking ownership * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Owner implements EntityComponent { public short ownerId; diff --git a/src/toniarts/openkeeper/game/component/Party.java b/src/toniarts/openkeeper/game/component/Party.java index 5caffe1d9..b3b8b2601 100644 --- a/src/toniarts/openkeeper/game/component/Party.java +++ b/src/toniarts/openkeeper/game/component/Party.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tags an entity to belong to a party * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Party implements EntityComponent { public long partyId; diff --git a/src/toniarts/openkeeper/game/component/PlayerObjective.java b/src/toniarts/openkeeper/game/component/PlayerObjective.java index 3d5520d5c..f2f3e515b 100644 --- a/src/toniarts/openkeeper/game/component/PlayerObjective.java +++ b/src/toniarts/openkeeper/game/component/PlayerObjective.java @@ -16,8 +16,10 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import toniarts.openkeeper.game.data.ObjectiveType; +import toniarts.openkeeper.game.network.Transferable; /** * Kinda a tagging component. Marks that this entity is a target for players (it @@ -25,6 +27,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class PlayerObjective implements EntityComponent { public ObjectiveType objective; diff --git a/src/toniarts/openkeeper/game/component/PortalGem.java b/src/toniarts/openkeeper/game/component/PortalGem.java index a1be09477..4c0766348 100644 --- a/src/toniarts/openkeeper/game/component/PortalGem.java +++ b/src/toniarts/openkeeper/game/component/PortalGem.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Basically a tagging component for owning a portal gem... Since nobody can't @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class PortalGem implements EntityComponent { public PortalGem() { diff --git a/src/toniarts/openkeeper/game/component/Position.java b/src/toniarts/openkeeper/game/component/Position.java index 51020506c..a13666068 100644 --- a/src/toniarts/openkeeper/game/component/Position.java +++ b/src/toniarts/openkeeper/game/component/Position.java @@ -17,13 +17,16 @@ package toniarts.openkeeper.game.component; import com.jme3.math.Vector3f; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Simple entity position class * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Position implements EntityComponent { public float rotation; // We are essentially 2D game, so around y-axis diff --git a/src/toniarts/openkeeper/game/component/RoomStorage.java b/src/toniarts/openkeeper/game/component/RoomStorage.java index 0157a979a..df016d7c6 100644 --- a/src/toniarts/openkeeper/game/component/RoomStorage.java +++ b/src/toniarts/openkeeper/game/component/RoomStorage.java @@ -16,14 +16,17 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import toniarts.openkeeper.game.controller.room.AbstractRoomController; +import toniarts.openkeeper.game.network.Transferable; /** * Tags an entity to be storaged on a room * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class RoomStorage implements EntityComponent { public AbstractRoomController.ObjectType objectType; diff --git a/src/toniarts/openkeeper/game/component/Senses.java b/src/toniarts/openkeeper/game/component/Senses.java index 6c7a4dce7..82d76e959 100644 --- a/src/toniarts/openkeeper/game/component/Senses.java +++ b/src/toniarts/openkeeper/game/component/Senses.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Senses, sensory system... Seeing & hearing. * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Senses implements EntityComponent { public float distanceCanHear; diff --git a/src/toniarts/openkeeper/game/component/Slapped.java b/src/toniarts/openkeeper/game/component/Slapped.java index d10e8cb34..f1439b927 100644 --- a/src/toniarts/openkeeper/game/component/Slapped.java +++ b/src/toniarts/openkeeper/game/component/Slapped.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Tagging component for something that has been slapped by the keeper * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Slapped implements EntityComponent { public double startTime; diff --git a/src/toniarts/openkeeper/game/component/Spellbook.java b/src/toniarts/openkeeper/game/component/Spellbook.java index 53010172c..8361ecc8a 100644 --- a/src/toniarts/openkeeper/game/component/Spellbook.java +++ b/src/toniarts/openkeeper/game/component/Spellbook.java @@ -16,8 +16,10 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import toniarts.openkeeper.game.data.ResearchableType; +import toniarts.openkeeper.game.network.Transferable; /** * Simple spellbook object. Spellbook holds research, that could be many @@ -25,6 +27,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Spellbook implements EntityComponent { public ResearchableType type; diff --git a/src/toniarts/openkeeper/game/component/TaskComponent.java b/src/toniarts/openkeeper/game/component/TaskComponent.java index ab07edafe..49f2ff8e1 100644 --- a/src/toniarts/openkeeper/game/component/TaskComponent.java +++ b/src/toniarts/openkeeper/game/component/TaskComponent.java @@ -16,9 +16,11 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; import com.simsilica.es.EntityId; import java.awt.Point; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.game.task.TaskType; /** @@ -26,6 +28,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class TaskComponent implements EntityComponent { public long taskId; diff --git a/src/toniarts/openkeeper/game/component/Threat.java b/src/toniarts/openkeeper/game/component/Threat.java index 7215b4287..42dbf73e9 100644 --- a/src/toniarts/openkeeper/game/component/Threat.java +++ b/src/toniarts/openkeeper/game/component/Threat.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Traps and creatures cause and have psychological effects that affects their @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Threat implements EntityComponent { public int threat; diff --git a/src/toniarts/openkeeper/game/component/TrapComponent.java b/src/toniarts/openkeeper/game/component/TrapComponent.java index 8a951114a..1d1c36310 100644 --- a/src/toniarts/openkeeper/game/component/TrapComponent.java +++ b/src/toniarts/openkeeper/game/component/TrapComponent.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * A base trap component * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class TrapComponent implements EntityComponent { public short trapId; diff --git a/src/toniarts/openkeeper/game/component/TrapViewState.java b/src/toniarts/openkeeper/game/component/TrapViewState.java index d6e572b76..30b9707cc 100644 --- a/src/toniarts/openkeeper/game/component/TrapViewState.java +++ b/src/toniarts/openkeeper/game/component/TrapViewState.java @@ -16,7 +16,9 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * Determines that the entity should be viewed as an trap. Visual presentation @@ -24,6 +26,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class TrapViewState implements EntityComponent { public short trapId; diff --git a/src/toniarts/openkeeper/game/component/Trigger.java b/src/toniarts/openkeeper/game/component/Trigger.java index 9e3f92bd7..d52e16350 100644 --- a/src/toniarts/openkeeper/game/component/Trigger.java +++ b/src/toniarts/openkeeper/game/component/Trigger.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.FieldSerializer; import com.simsilica.es.EntityComponent; +import toniarts.openkeeper.game.network.Transferable; /** * An entity class marking trigger * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Trigger implements EntityComponent { public int triggerId; diff --git a/src/toniarts/openkeeper/game/component/ViewType.java b/src/toniarts/openkeeper/game/component/ViewType.java index 7d2df4146..4277236b6 100644 --- a/src/toniarts/openkeeper/game/component/ViewType.java +++ b/src/toniarts/openkeeper/game/component/ViewType.java @@ -16,11 +16,15 @@ */ package toniarts.openkeeper.game.component; +import com.jme3.network.serializing.serializers.EnumSerializer; +import toniarts.openkeeper.game.network.Transferable; + /** * Signifies the view/record type of an object * * @author Toni Helenius */ +@Transferable(EnumSerializer.class) public enum ViewType { CREATURE, OBJECT, diff --git a/src/toniarts/openkeeper/game/controller/GameWorldController.java b/src/toniarts/openkeeper/game/controller/GameWorldController.java index e8cbd10a0..8a772ed6a 100644 --- a/src/toniarts/openkeeper/game/controller/GameWorldController.java +++ b/src/toniarts/openkeeper/game/controller/GameWorldController.java @@ -75,6 +75,7 @@ import toniarts.openkeeper.tools.convert.map.Tile; import toniarts.openkeeper.tools.convert.map.Variable; import toniarts.openkeeper.utils.WorldUtils; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Game world controller, controls the game world related actions @@ -119,7 +120,7 @@ public void createNewGame(IGameController gameController, ILevelInfo levelInfo) objectsController = new ObjectsController(kwdFile, entityData, gameSettings, gameTimer, gameController); // Load the map - mapController = new MapController(kwdFile, objectsController, gameSettings, gameTimer); + mapController = new MapController(kwdFile, objectsController, gameSettings, gameTimer, this); // Load creatures creaturesController = new CreaturesController(kwdFile, entityData, gameSettings, gameTimer, gameController, mapController, levelInfo); @@ -303,23 +304,23 @@ private void addGoldCapacityToPlayer(RoomInstance instance) { } @Override - public void build(Vector2f start, Vector2f end, short playerId, short roomId) { + public void build(SelectionArea area, short playerId, short roomId) { + if (mapController.isBuildable(area, playerId, roomId)) { + mapController.buildOrSellRoom(area, playerId, roomId); + } + } + + @Override + public void build(Set points, short playerId, short roomId) { List instancePlots = new ArrayList<>(); - int x1 = (int) Math.max(0, start.x); - int x2 = (int) Math.min(kwdFile.getMap().getWidth(), end.x + 1); - int y1 = (int) Math.max(0, start.y); - int y2 = (int) Math.min(kwdFile.getMap().getHeight(), end.y + 1); - for (int x = x1; x < x2; x++) { - for (int y = y1; y < y2; y++) { - Point p = new Point(x, y); - - // See that is this valid - if (!mapController.isBuildable(p, playerId, roomId)) { - continue; - } - instancePlots.add(p); + for (Point p : points) { + // See that is this valid + if (!mapController.isBuildable(p, playerId, roomId)) { + continue; } + + instancePlots.add(p); } // If no plots, no building @@ -329,11 +330,6 @@ public void build(Vector2f start, Vector2f end, short playerId, short roomId) { // If this is a bridge, we only got the starting point(s) as valid so we need to determine valid bridge pieces by our ourselves Room room = kwdFile.getRoomById(roomId); - if ((room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_WATER)) - || room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAVA)) { - instancePlots = new ArrayList(mapController.getTerrainBatches(instancePlots, x1, x2, y1, y2)); - } - // See that can we afford the building synchronized (GOLD_LOCK) { int cost = instancePlots.size() * room.getCost(); @@ -424,48 +420,53 @@ public void build(Vector2f start, Vector2f end, short playerId, short roomId) { } @Override - public void sell(Vector2f start, Vector2f end, short playerId) { + public void sell(SelectionArea area, short playerId) { + // FIXME does not work isSellable +// if (mapController.isSellable(area, playerId)) { + mapController.buildOrSellRoom(area, playerId); +// } + } + + @Override + public void sell(Set points, short playerId) { List soldTiles = new ArrayList<>(); Set updatableTiles = new HashSet<>(); Set soldInstances = new HashSet<>(); List roomCoordinates = new ArrayList<>(); List> moneyToReturnByPoint = new ArrayList<>(); - for (int x = (int) Math.max(0, start.x); x < Math.min(kwdFile.getMap().getWidth(), end.x + 1); x++) { - for (int y = (int) Math.max(0, start.y); y < Math.min(kwdFile.getMap().getHeight(), end.y + 1); y++) { - Point p = new Point(x, y); - // See that is this valid - if (!mapController.isSellable(p, playerId)) { - continue; - } - - // Sell - MapTile tile = mapController.getMapData().getTile(p); - if (tile == null) { - continue; - } - soldTiles.add(tile); - - Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); - if (terrain.getFlags().contains(Terrain.TerrainFlag.ROOM)) { - Room room = kwdFile.getRoomByTerrain(tile.getTerrainId()); - if (room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAND)) { - tile.setTerrainId(terrain.getDestroyedTypeTerrainId()); - } else // Water or lava - if (tile.getBridgeTerrainType() == Tile.BridgeTerrainType.LAVA) { - tile.setTerrainId(kwdFile.getMap().getLava().getTerrainId()); - } else { - tile.setTerrainId(kwdFile.getMap().getWater().getTerrainId()); - } + for (Point p : points) { + // See that is this valid + if (!mapController.isSellable(p, playerId)) { + continue; + } - // Money back - moneyToReturnByPoint.add(new AbstractMap.SimpleImmutableEntry<>(p, (int) (room.getCost() * (gameSettings.get(Variable.MiscVariable.MiscType.ROOM_SELL_VALUE_PERCENTAGE_OF_COST).getValue() / 100)))); + // Sell + MapTile tile = mapController.getMapData().getTile(p); + if (tile == null) { + continue; + } + soldTiles.add(tile); + + Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); + if (terrain.getFlags().contains(Terrain.TerrainFlag.ROOM)) { + Room room = kwdFile.getRoomByTerrain(tile.getTerrainId()); + if (room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAND)) { + tile.setTerrainId(terrain.getDestroyedTypeTerrainId()); + } else // Water or lava + if (tile.getBridgeTerrainType() == Tile.BridgeTerrainType.LAVA) { + tile.setTerrainId(kwdFile.getMap().getLava().getTerrainId()); + } else { + tile.setTerrainId(kwdFile.getMap().getWater().getTerrainId()); } - // Get the instance - soldInstances.add(mapController.getRoomCoordinates().get(p)); - updatableTiles.addAll(Arrays.asList(WorldUtils.getSurroundingTiles(mapController.getMapData(), p, true))); + // Money back + moneyToReturnByPoint.add(new AbstractMap.SimpleImmutableEntry<>(p, (int) (room.getCost() * (gameSettings.get(Variable.MiscVariable.MiscType.ROOM_SELL_VALUE_PERCENTAGE_OF_COST).getValue() / 100)))); } + + // Get the instance + soldInstances.add(mapController.getRoomCoordinates().get(p)); + updatableTiles.addAll(Arrays.asList(WorldUtils.getSurroundingTiles(mapController.getMapData(), p, true))); } // See if we did anything at all @@ -531,8 +532,8 @@ private void removeRoomInstance(RoomInstance roomInstance) { } @Override - public void selectTiles(Vector2f start, Vector2f end, boolean select, short playerId) { - mapController.selectTiles(start, end, select, playerId); + public void selectTiles(SelectionArea area, short playerId) { + mapController.selectTiles(area, playerId); } @Override diff --git a/src/toniarts/openkeeper/game/controller/IBuildOrSellRoom.java b/src/toniarts/openkeeper/game/controller/IBuildOrSellRoom.java new file mode 100644 index 000000000..5a0f45a8f --- /dev/null +++ b/src/toniarts/openkeeper/game/controller/IBuildOrSellRoom.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014-2020 OpenKeeper + * + * OpenKeeper is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenKeeper is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenKeeper. If not, see . + */ +package toniarts.openkeeper.game.controller; + +import java.awt.Point; +import java.util.Set; + +/** + * + * @author ArchDemon + */ +public interface IBuildOrSellRoom { + + public void build(Set points, short playerId, short roomId); + + public void sell(Set points, short playerId); +} diff --git a/src/toniarts/openkeeper/game/controller/IGameWorldController.java b/src/toniarts/openkeeper/game/controller/IGameWorldController.java index f4ea7f995..0f8109759 100644 --- a/src/toniarts/openkeeper/game/controller/IGameWorldController.java +++ b/src/toniarts/openkeeper/game/controller/IGameWorldController.java @@ -20,13 +20,14 @@ import com.simsilica.es.EntityId; import java.awt.Point; import toniarts.openkeeper.game.listener.PlayerActionListener; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Controls the game world, map and the entities * * @author Toni Helenius */ -public interface IGameWorldController { +public interface IGameWorldController extends IBuildOrSellRoom { /** * Add a lump sum of gold to a player, distributes the gold to the available @@ -89,21 +90,19 @@ public interface IGameWorldController { /** * Build a building to the wanted area * - * @param start start location - * @param end end location + * @param area * @param playerId the player who is building the room * @param roomId the room ID to be build */ - public void build(Vector2f start, Vector2f end, short playerId, short roomId); + public void build(SelectionArea area, short playerId, short roomId); /** * Sell a building from wanted area * - * @param start start location - * @param end end location + * @param area * @param playerId the player who is selling the room */ - public void sell(Vector2f start, Vector2f end, short playerId); + public void sell(SelectionArea area, short playerId); /** * Interact with given entity diff --git a/src/toniarts/openkeeper/game/controller/IMapController.java b/src/toniarts/openkeeper/game/controller/IMapController.java index 631b434ed..18f82b46d 100644 --- a/src/toniarts/openkeeper/game/controller/IMapController.java +++ b/src/toniarts/openkeeper/game/controller/IMapController.java @@ -1,11 +1,21 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Copyright (C) 2014-2018 OpenKeeper + * + * OpenKeeper is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenKeeper is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenKeeper. If not, see . */ package toniarts.openkeeper.game.controller; -import com.jme3.math.Vector2f; import java.awt.Point; import java.util.Collection; import java.util.List; @@ -19,6 +29,7 @@ import toniarts.openkeeper.game.listener.RoomListener; import toniarts.openkeeper.game.logic.IGameLogicUpdatable; import toniarts.openkeeper.game.map.IMapInformation; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Map related actions available to all players @@ -30,12 +41,10 @@ public interface IMapController extends IMapInformation, IGameLogicUpdatable { /** * Set some tiles selected/undelected * - * @param start start coordinates - * @param end end coordinates - * @param select select or unselect + * @param area * @param playerId the player who selected the tile */ - void selectTiles(Vector2f start, Vector2f end, boolean select, short playerId); + void selectTiles(SelectionArea area, short playerId); /** * If you want to get notified about tile changes @@ -183,7 +192,7 @@ public interface IMapController extends IMapInformation, IGameLogicUpdatable { * * @param points the points to flash * @param playerId the player whose flashing will be affected - * @param time the time to flash + * @param time the time to flash */ public void flashTiles(List points, short playerId, int time); @@ -209,4 +218,8 @@ public interface IMapController extends IMapInformation, IGameLogicUpdatable { */ public Set getTerrainBatches(List startingPoints, int x1, int x2, int y1, int y2); + public void buildOrSellRoom(SelectionArea area, short playerId, short roomId); + + public void buildOrSellRoom(SelectionArea area, short playerId); + } diff --git a/src/toniarts/openkeeper/game/controller/IPlayerActions.java b/src/toniarts/openkeeper/game/controller/IPlayerActions.java index ee5ea99c7..95541c60d 100644 --- a/src/toniarts/openkeeper/game/controller/IPlayerActions.java +++ b/src/toniarts/openkeeper/game/controller/IPlayerActions.java @@ -17,6 +17,7 @@ package toniarts.openkeeper.game.controller; import com.jme3.math.Vector2f; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Holds together all game related player actions @@ -28,30 +29,26 @@ public interface IPlayerActions { /** * Build a building to the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area * @param playerId the player, the new owner * @param roomId room to build */ - public void build(Vector2f start, Vector2f end, short playerId, short roomId); + public void build(SelectionArea area, short playerId, short roomId); /** * Sell building(s) from the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area * @param playerId the player, the seller */ - public void sell(Vector2f start, Vector2f end, short playerId); + public void sell(SelectionArea area, short playerId); /** * Set some tiles selected/undelected * - * @param start start coordinates - * @param end end coordinates - * @param select select or unselect + * @param area * @param playerId the player who selected the tile */ - public void selectTiles(Vector2f start, Vector2f end, boolean select, short playerId); + public void selectTiles(SelectionArea area, short playerId); } diff --git a/src/toniarts/openkeeper/game/controller/MapController.java b/src/toniarts/openkeeper/game/controller/MapController.java index 1bc5c4d5d..3ce9a32f3 100644 --- a/src/toniarts/openkeeper/game/controller/MapController.java +++ b/src/toniarts/openkeeper/game/controller/MapController.java @@ -21,7 +21,6 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; -import com.jme3.math.Vector2f; import com.jme3.util.SafeArrayList; import java.awt.Point; import java.io.IOException; @@ -29,12 +28,14 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import toniarts.openkeeper.common.RoomInstance; import toniarts.openkeeper.game.control.Container; import toniarts.openkeeper.game.controller.creature.ICreatureController; +import toniarts.openkeeper.game.controller.map.BuildTileControl; import toniarts.openkeeper.game.controller.map.FlashTileControl; import toniarts.openkeeper.game.controller.room.AbstractRoomController.ObjectType; import toniarts.openkeeper.game.controller.room.IRoomController; @@ -48,6 +49,7 @@ import toniarts.openkeeper.tools.convert.map.Terrain; import toniarts.openkeeper.tools.convert.map.Variable; import toniarts.openkeeper.utils.WorldUtils; +import toniarts.openkeeper.view.selection.SelectionArea; /** * This is controller for the map related functions @@ -73,28 +75,29 @@ public MapController() { /** * Load map data from a KWD file straight (new game) * - * @param kwdFile the KWD file + * @param kwdFile the KWD file * @param objectsController objects controller - * @param gameSettings the game settings + * @param gameSettings the game settings * @param gameTimer + * @param gameWorldController */ public MapController(KwdFile kwdFile, IObjectsController objectsController, Map gameSettings, - IGameTimer gameTimer) { + IGameTimer gameTimer, IBuildOrSellRoom gameWorldController) { this.kwdFile = kwdFile; this.objectsController = objectsController; this.mapData = new MapData(kwdFile); this.gameSettings = gameSettings; this.gameTimer = gameTimer; - // Load rooms loadRooms(); + addControl(new BuildTileControl(gameWorldController)); } /** * Instantiate a map controller from map data (loaded game) * - * @param mapData the map data - * @param kwdFile the KWD file + * @param mapData the map data + * @param kwdFile the KWD file * @param gameSettings the game settings */ public MapController(MapData mapData, KwdFile kwdFile, Map gameSettings, IGameTimer gameTimer) { @@ -110,29 +113,26 @@ public MapController(MapData mapData, KwdFile kwdFile) { } private void loadRooms() { - // Go through the tiles and detect any rooms - for (int y = 0; y < mapData.getHeight(); y++) { - for (int x = 0; x < mapData.getWidth(); x++) { - loadRoom(new Point(x, y)); - } + for (MapTile tile : mapData) { + loadRoom(tile); } } - private void loadRoom(Point p) { - MapTile mapTile = mapData.getTile(p); + private void loadRoom(MapTile mapTile) { + // check flag if (!kwdFile.getTerrain(mapTile.getTerrainId()).getFlags().contains(Terrain.TerrainFlag.ROOM)) { return; } - if (roomCoordinates.containsKey(p)) { + if (roomCoordinates.containsKey(mapTile.getLocation())) { return; } // Find it RoomInstance roomInstance = new RoomInstance(kwdFile.getRoomByTerrain(mapTile.getTerrainId())); roomInstance.setOwnerId(mapTile.getOwnerId()); - findRoom(p, roomInstance); + findRoom(mapTile.getLocation(), roomInstance); // Create a controller for it IRoomController roomController = RoomControllerFactory.constructRoom(kwdFile, roomInstance, objectsController, gameSettings, gameTimer); @@ -141,9 +141,8 @@ private void loadRoom(Point p) { // TODO: A bit of a design problem here /** - * Unclear responsibilities between the world and map controller. - * Also a result of how we handle the building and selling by - * destroying rooms. + * Unclear responsibilities between the world and map controller. Also a + * result of how we handle the building and selling by destroying rooms. * But at least keep anyone who is listening intact */ notifyOnBuild(roomController.getRoomInstance().getOwnerId(), roomController); @@ -153,7 +152,7 @@ private void loadRoom(Point p) { * Find the room starting from a certain point, rooms are never diagonally * attached * - * @param p starting point + * @param p starting point * @param roomInstance the room instance */ private void findRoom(Point p, RoomInstance roomInstance) { @@ -261,21 +260,22 @@ private void notifyOnSold(short playerId, IRoomController room) { } @Override - public void selectTiles(Vector2f start, Vector2f end, boolean select, short playerId) { + public void selectTiles(SelectionArea area, short playerId) { List updatableTiles = new ArrayList<>(); - for (int x = (int) Math.max(0, start.x); x < Math.min(kwdFile.getMap().getWidth(), end.x + 1); x++) { - for (int y = (int) Math.max(0, start.y); y < Math.min(kwdFile.getMap().getHeight(), end.y + 1); y++) { - MapTile tile = getMapData().getTile(x, y); - if (tile == null) { - continue; - } - Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); - if (!terrain.getFlags().contains(Terrain.TerrainFlag.TAGGABLE)) { - continue; - } - tile.setSelected(select, playerId); - updatableTiles.add(tile); + MapTile startTile = getMapData().getTile(WorldUtils.vectorToPoint(area.getRealStart())); + boolean select = (startTile == null) ? true : !startTile.isSelected(playerId); + + for (Iterator it = area.simpleIterator(); it.hasNext();) { + MapTile tile = getMapData().getTile(it.next()); + if (tile == null) { + continue; + } + Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); + if (!terrain.getFlags().contains(Terrain.TerrainFlag.TAGGABLE)) { + continue; } + tile.setSelected(select, playerId); + updatableTiles.add(tile); } //Point[] tiles = updatableTiles.toArray(new Point[updatableTiles.size()]); //mapLoader.updateTiles(tiles); @@ -303,6 +303,14 @@ public boolean isTaggable(Point p) { return terrain.getFlags().contains(Terrain.TerrainFlag.TAGGABLE); } + /** + * Does not check adjacent to own tile + * + * @param p location + * @param playerId + * @param roomId + * @return + */ @Override public boolean isBuildable(Point p, short playerId, short roomId) { MapTile tile = getMapData().getTile(p); @@ -326,8 +334,7 @@ public boolean isBuildable(Point p, short playerId, short roomId) { if ((room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_WATER) && terrain.getFlags().contains(Terrain.TerrainFlag.WATER)) || room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAVA) && terrain.getFlags().contains(Terrain.TerrainFlag.LAVA)) { - // We need to have an adjacent owned tile - return hasAdjacentOwnedPath(tile.getLocation(), playerId); + return true; } return false; @@ -413,7 +420,7 @@ public boolean isLava(Point p) { return false; } Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); - return terrain.getFlags().contains(Terrain.TerrainFlag.LAVA); + return terrain.getFlags().contains(Terrain.TerrainFlag.LAVA); } @Override @@ -485,8 +492,8 @@ public void removeRoomInstances(RoomInstance... instances) { /** * Unclear responsibilities between the world and map controller. * Also a result of how we handle the building and selling by - * destroying rooms. - * But at least keep anyone who is listening intact + * destroying rooms. But at least keep anyone who is listening + * intact */ notifyOnSold(roomController.getRoomInstance().getOwnerId(), roomController); } @@ -496,7 +503,7 @@ public void removeRoomInstances(RoomInstance... instances) { * Get rooms by function.
FIXME: Should the player have ready lists? * * @param objectType the function - * @param playerId the player id, can be null + * @param playerId the player id, can be null * @return list of rooms that match the criteria */ @Override @@ -516,7 +523,7 @@ public List getRoomsByFunction(ObjectType objectType, Short pla @Override public void updateRooms(Point[] coordinates) { for (Point p : coordinates) { - loadRoom(p); + loadRoom(mapData.getTile(p)); } } @@ -661,7 +668,7 @@ public int damageTile(Point point, short playerId, ICreatureController creature) /** * Heal a tile * - * @param point the point + * @param point the point * @param playerId the player applying the healing */ @Override @@ -723,7 +730,7 @@ public void healTile(Point point, short playerId) { /** * Damage a room * - * @param point tile coordinate + * @param point tile coordinate * @param playerId for the player */ private void damageRoom(Point point, short playerId) { @@ -855,6 +862,16 @@ public void flashTiles(List points, short playerId, int time) { } } + @Override + public void buildOrSellRoom(SelectionArea area, short playerId, short roomId) { + getControl(BuildTileControl.class).add(area, playerId, roomId); + } + + @Override + public void buildOrSellRoom(SelectionArea area, short playerId) { + buildOrSellRoom(area, playerId, (short) 0); + } + @Override public void unFlashTiles(List points, short playerId) { List tilesToUpdate = new ArrayList<>(points.size()); @@ -948,4 +965,58 @@ private void findTerrainBatch(Point p, Short terrainId, Set batches, int } } } + + @Override + public boolean isSellable(SelectionArea selectionArea, short playerId) { + for (Iterator it = selectionArea.simpleIterator(); it.hasNext();) { + Point p = it.next(); + + MapTile tile = getMapData().getTile(p); + if (tile != null && isSellable(p, playerId)) { + return true; + } + } + + return false; + } + + @Override + public boolean isBuildable(SelectionArea selectionArea, short playerId, short roomId) { + + for (Iterator it = selectionArea.simpleIterator(); it.hasNext();) { + Point p = it.next(); + + MapTile tile = getMapData().getTile(p); + if (tile == null) { + continue; + } + + Room room = kwdFile.getRoomById(roomId); + Terrain terrain = kwdFile.getTerrain(tile.getTerrainId()); + + // Ownable tile is needed for land building (and needs to be owned by us) + if (room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAND) + && !terrain.getFlags().contains(Terrain.TerrainFlag.SOLID) + && terrain.getFlags().contains(Terrain.TerrainFlag.OWNABLE) + && !terrain.getFlags().contains(Terrain.TerrainFlag.ROOM) + && tile.getOwnerId() == playerId) { + return true; + } + + // See if we are dealing with bridges + if ((room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_WATER) + && terrain.getFlags().contains(Terrain.TerrainFlag.WATER)) + || room.getFlags().contains(Room.RoomFlag.PLACEABLE_ON_LAVA) + && terrain.getFlags().contains(Terrain.TerrainFlag.LAVA)) { + + // We need to have an adjacent owned tile + boolean adjacent = hasAdjacentOwnedPath(tile.getLocation(), playerId); + if (adjacent) { + return true; + } + } + } + + return false; + } } diff --git a/src/toniarts/openkeeper/game/controller/map/BuildTileControl.java b/src/toniarts/openkeeper/game/controller/map/BuildTileControl.java new file mode 100644 index 000000000..91407891a --- /dev/null +++ b/src/toniarts/openkeeper/game/controller/map/BuildTileControl.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2014-2020 OpenKeeper + * + * OpenKeeper is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenKeeper is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenKeeper. If not, see . + */ +package toniarts.openkeeper.game.controller.map; + +import java.awt.Point; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import toniarts.openkeeper.game.control.Control; +import toniarts.openkeeper.game.controller.IBuildOrSellRoom; +import toniarts.openkeeper.view.selection.SelectionArea; + +/** + * + * @author ArchDemon + */ +public class BuildTileControl extends Control { + + private float tick = 0; + public final float PERIOD = 0.3f; + private IBuildOrSellRoom gameWorldController; + private final Queue queue = new ArrayDeque<>(); + + public BuildTileControl() { + // nope + } + + public BuildTileControl(final IBuildOrSellRoom gameWorldController) { + this.gameWorldController = gameWorldController; + } + + public boolean add(final SelectionArea area, final short playerId, final short room) { + List items = new ArrayList<>(); + + for (Set p : area) { + items.add(new Item(p, playerId, room)); + } + + synchronized (this.queue) { + return this.queue.addAll(items); + } + } + + @Override + protected void updateControl(float tpf) { + if (!isEnabled() || queue.isEmpty()) { + return; + } + + if (tick >= PERIOD) { + tick -= PERIOD; + synchronized (this.queue) { + Item item = queue.poll(); + if (item.isBuild()) { + gameWorldController.build(item.getPoints(), item.getPlayerId(), item.getRoomId()); + } else { + gameWorldController.sell(item.getPoints(), item.getPlayerId()); + } + } + } + + tick += tpf; + } + + public static class Item { + + private final Set points; + private final short playerId; + private final short roomId; + + public Item(Set points, short playerId, short roomId) { + this.points = points; + this.playerId = playerId; + this.roomId = roomId; + } + + public Set getPoints() { + return points; + } + + public short getPlayerId() { + return playerId; + } + + public short getRoomId() { + return roomId; + } + + public boolean isBuild() { + return roomId != 0; + } + + } +} diff --git a/src/toniarts/openkeeper/game/controller/room/AbstractRoomController.java b/src/toniarts/openkeeper/game/controller/room/AbstractRoomController.java index 7fc27baf2..46f0bf90d 100644 --- a/src/toniarts/openkeeper/game/controller/room/AbstractRoomController.java +++ b/src/toniarts/openkeeper/game/controller/room/AbstractRoomController.java @@ -16,6 +16,7 @@ */ package toniarts.openkeeper.game.controller.room; +import com.jme3.network.serializing.serializers.EnumSerializer; import com.simsilica.es.EntityId; import java.awt.Point; import java.util.Collections; @@ -27,6 +28,7 @@ import toniarts.openkeeper.common.RoomInstance; import toniarts.openkeeper.game.controller.IObjectsController; import toniarts.openkeeper.game.controller.room.storage.IRoomObjectControl; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.KwdFile; import toniarts.openkeeper.tools.convert.map.Room; @@ -40,6 +42,7 @@ public abstract class AbstractRoomController implements IRoomController { /** * The type of object the room houses */ + @Transferable(EnumSerializer.class) public enum ObjectType { GOLD, LAIR, SPELL_BOOK, RESEARCHER, PRISONER, TORTUREE, FOOD; diff --git a/src/toniarts/openkeeper/game/data/ActionPoint.java b/src/toniarts/openkeeper/game/data/ActionPoint.java index 0d1233a56..b5ff199d8 100644 --- a/src/toniarts/openkeeper/game/data/ActionPoint.java +++ b/src/toniarts/openkeeper/game/data/ActionPoint.java @@ -20,7 +20,9 @@ import java.awt.Point; import java.util.ArrayList; import java.util.EnumSet; +import java.util.Iterator; import java.util.List; +import java.util.function.Consumer; import toniarts.openkeeper.game.control.Container; import toniarts.openkeeper.tools.convert.map.Thing; @@ -29,7 +31,7 @@ * * @author ArchDemon */ -public class ActionPoint extends Container implements ITriggerable { +public class ActionPoint extends Container implements ITriggerable, Iterable { private final int id; private final int triggerId; @@ -39,7 +41,7 @@ public class ActionPoint extends Container implements ITriggerable { private final int waitDelay; private final int nextWaypointId; private final Vector2f center; - private final List points; + private List points; public ActionPoint(Thing.ActionPoint acionPoint) { id = acionPoint.getId(); @@ -49,14 +51,6 @@ public ActionPoint(Thing.ActionPoint acionPoint) { nextWaypointId = acionPoint.getNextWaypointId(); flags = acionPoint.getFlags(); triggerId = acionPoint.getTriggerId(); - - points = new ArrayList<>((end.x - start.x + 1) * (end.y - start.y + 1)); - for (int x = start.x; x <= end.x; x++) { - for (int y = start.y; y <= end.y; y++) { - points.add(new Point(x, y)); - } - } - center = new Vector2f((start.x + end.x) / 2, (start.y + end.y) / 2); } @@ -94,6 +88,14 @@ public Vector2f getCenter() { } public List getPoints() { + if (points == null) { + points = new ArrayList<>((end.x - start.x + 1) * (end.y - start.y + 1)); + for (int x = start.x; x <= end.x; x++) { + for (int y = start.y; y <= end.y; y++) { + points.add(new Point(x, y)); + } + } + } return points; } @@ -102,4 +104,46 @@ public String toString() { return "ActionPoint { id=" + id + ", triggerId=" + triggerId + ", start=" + start + ", end=" + end + ", flags=" + flags + ", waitDelay=" + waitDelay + ", nextWaypointId=" + nextWaypointId + " }"; } + + @Override + public Iterator iterator() { + return new ActionPointIterator(); + } + + private class ActionPointIterator implements Iterator { + + private Point cursor; + + @Override + public boolean hasNext() { + return !ActionPoint.this.end.equals(cursor); + } + + @Override + public Point next() { + + if (cursor == null) { + cursor = (Point) ActionPoint.this.start.clone(); + return cursor; + } + + cursor.x++; + if (cursor.x > end.x) { + cursor.x = start.x; + cursor.y++; + } + + return cursor; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public void forEachRemaining(Consumer consumer) { + throw new UnsupportedOperationException(); + } + } } diff --git a/src/toniarts/openkeeper/game/data/Keeper.java b/src/toniarts/openkeeper/game/data/Keeper.java index 4d2856b29..cb1733a62 100644 --- a/src/toniarts/openkeeper/game/data/Keeper.java +++ b/src/toniarts/openkeeper/game/data/Keeper.java @@ -21,6 +21,7 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.awt.Point; import java.io.IOException; import java.util.ArrayList; @@ -28,6 +29,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.AI.AIType; import toniarts.openkeeper.tools.convert.map.Player; @@ -36,6 +38,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class Keeper implements Comparable, IIndexable, Savable { private boolean ai; diff --git a/src/toniarts/openkeeper/game/data/ObjectiveType.java b/src/toniarts/openkeeper/game/data/ObjectiveType.java index a2470cde4..26cd3ec9d 100644 --- a/src/toniarts/openkeeper/game/data/ObjectiveType.java +++ b/src/toniarts/openkeeper/game/data/ObjectiveType.java @@ -16,11 +16,15 @@ */ package toniarts.openkeeper.game.data; +import com.jme3.network.serializing.serializers.EnumSerializer; +import toniarts.openkeeper.game.network.Transferable; + /** * Player objective for a target * * @author Toni Helenius */ +@Transferable(EnumSerializer.class) public enum ObjectiveType { KILL, IMPRISON, CONVERT; diff --git a/src/toniarts/openkeeper/game/data/PlayerSpell.java b/src/toniarts/openkeeper/game/data/PlayerSpell.java index eb5bb0f7f..e0a5ad66c 100644 --- a/src/toniarts/openkeeper/game/data/PlayerSpell.java +++ b/src/toniarts/openkeeper/game/data/PlayerSpell.java @@ -20,13 +20,16 @@ import com.jme3.export.JmeExporter; import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.io.IOException; +import toniarts.openkeeper.game.network.Transferable; /** * Player's spell (Keeper Spell) * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class PlayerSpell extends ResearchableEntity { public PlayerSpell() { diff --git a/src/toniarts/openkeeper/game/data/ResearchableEntity.java b/src/toniarts/openkeeper/game/data/ResearchableEntity.java index 3ffe345a6..0e34dcca8 100644 --- a/src/toniarts/openkeeper/game/data/ResearchableEntity.java +++ b/src/toniarts/openkeeper/game/data/ResearchableEntity.java @@ -21,13 +21,16 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.io.IOException; +import toniarts.openkeeper.game.network.Transferable; /** * Represents a researchable item such as keeper spell, room, trap, etc * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ResearchableEntity implements Savable { protected short id; diff --git a/src/toniarts/openkeeper/game/data/ResearchableType.java b/src/toniarts/openkeeper/game/data/ResearchableType.java index 035b7bc0a..66304a9df 100644 --- a/src/toniarts/openkeeper/game/data/ResearchableType.java +++ b/src/toniarts/openkeeper/game/data/ResearchableType.java @@ -16,11 +16,15 @@ */ package toniarts.openkeeper.game.data; +import com.jme3.network.serializing.serializers.EnumSerializer; +import toniarts.openkeeper.game.network.Transferable; + /** * Type of researchable entity * * @author Toni Helenius */ +@Transferable(EnumSerializer.class) public enum ResearchableType { ROOM, SPELL, DOOR, TRAP; diff --git a/src/toniarts/openkeeper/game/logic/ManaCalculatorLogic.java b/src/toniarts/openkeeper/game/logic/ManaCalculatorLogic.java index 700fcf5a4..78c643aaa 100644 --- a/src/toniarts/openkeeper/game/logic/ManaCalculatorLogic.java +++ b/src/toniarts/openkeeper/game/logic/ManaCalculatorLogic.java @@ -79,12 +79,9 @@ private void reset() { private void calculateGainFromMapTiles() { MapData mapData = mapController.getMapData(); - for (int x = 0; x < mapData.getWidth(); x++) { - for (int y = 0; y < mapData.getHeight(); y++) { - MapTile tile = mapData.getTile(x, y); - if (manaGains.containsKey(tile.getOwnerId())) { - manaGains.put(tile.getOwnerId(), manaGains.get(tile.getOwnerId()) + tile.getManaGain()); - } + for (MapTile tile : mapData) { + if (manaGains.containsKey(tile.getOwnerId())) { + manaGains.put(tile.getOwnerId(), manaGains.get(tile.getOwnerId()) + tile.getManaGain()); } } } diff --git a/src/toniarts/openkeeper/game/map/IMapInformation.java b/src/toniarts/openkeeper/game/map/IMapInformation.java index fcf0250a2..61a820b81 100644 --- a/src/toniarts/openkeeper/game/map/IMapInformation.java +++ b/src/toniarts/openkeeper/game/map/IMapInformation.java @@ -19,6 +19,7 @@ import java.awt.Point; import java.util.List; import toniarts.openkeeper.tools.convert.map.Terrain; +import toniarts.openkeeper.view.selection.SelectionArea; /** * A kind of a map container with no editing functionalities @@ -147,4 +148,7 @@ public interface IMapInformation { */ public boolean isLava(Point p); + public boolean isSellable(SelectionArea selectionArea, short playerId); + + public boolean isBuildable(SelectionArea selectionArea, short playerId, short roomId); } diff --git a/src/toniarts/openkeeper/game/map/MapData.java b/src/toniarts/openkeeper/game/map/MapData.java index 3c13d82d3..47f8c773b 100644 --- a/src/toniarts/openkeeper/game/map/MapData.java +++ b/src/toniarts/openkeeper/game/map/MapData.java @@ -21,11 +21,13 @@ import com.jme3.export.JmeImporter; import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.awt.Point; import java.io.IOException; import java.util.Iterator; import java.util.List; import java.util.function.Consumer; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.KwdFile; import toniarts.openkeeper.tools.convert.map.Tile; @@ -34,6 +36,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) // FIXME: SavableSerializer would be better... public class MapData implements Savable, Iterable { private int width; diff --git a/src/toniarts/openkeeper/game/map/MapTile.java b/src/toniarts/openkeeper/game/map/MapTile.java index 58e2b2efc..a96c09451 100644 --- a/src/toniarts/openkeeper/game/map/MapTile.java +++ b/src/toniarts/openkeeper/game/map/MapTile.java @@ -22,11 +22,13 @@ import com.jme3.export.OutputCapsule; import com.jme3.export.Savable; import com.jme3.math.FastMath; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.awt.Point; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.stream.IntStream; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.map.Terrain; import toniarts.openkeeper.tools.convert.map.Tile; import toniarts.openkeeper.tools.convert.map.Tile.BridgeTerrainType; @@ -36,6 +38,7 @@ * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class MapTile implements Savable { private Map selection = new HashMap<>(); diff --git a/src/toniarts/openkeeper/game/network/NetworkServer.java b/src/toniarts/openkeeper/game/network/NetworkServer.java index 94ea39773..ec76721ff 100644 --- a/src/toniarts/openkeeper/game/network/NetworkServer.java +++ b/src/toniarts/openkeeper/game/network/NetworkServer.java @@ -22,7 +22,6 @@ import com.jme3.network.Network; import com.jme3.network.Server; import com.jme3.network.serializing.Serializer; -import com.jme3.network.serializing.serializers.EnumSerializer; import com.jme3.network.serializing.serializers.FieldSerializer; import com.jme3.network.service.HostedService; import com.jme3.network.service.rmi.RmiHostedService; @@ -34,74 +33,12 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import toniarts.openkeeper.game.component.AttackTarget; -import toniarts.openkeeper.game.component.ChickenAi; -import toniarts.openkeeper.game.component.ChickenGenerator; -import toniarts.openkeeper.game.component.CreatureAi; -import toniarts.openkeeper.game.component.CreatureComponent; -import toniarts.openkeeper.game.component.CreatureEfficiency; -import toniarts.openkeeper.game.component.CreatureExperience; -import toniarts.openkeeper.game.component.CreatureFall; -import toniarts.openkeeper.game.component.CreatureHunger; -import toniarts.openkeeper.game.component.CreatureImprisoned; -import toniarts.openkeeper.game.component.CreatureMeleeAttack; -import toniarts.openkeeper.game.component.CreatureMood; -import toniarts.openkeeper.game.component.CreatureRecuperating; -import toniarts.openkeeper.game.component.CreatureSleep; -import toniarts.openkeeper.game.component.CreatureTortured; -import toniarts.openkeeper.game.component.CreatureViewState; -import toniarts.openkeeper.game.component.Death; -import toniarts.openkeeper.game.component.Decay; -import toniarts.openkeeper.game.component.DoorComponent; -import toniarts.openkeeper.game.component.DoorViewState; -import toniarts.openkeeper.game.component.Fearless; -import toniarts.openkeeper.game.component.FollowTarget; -import toniarts.openkeeper.game.component.Food; -import toniarts.openkeeper.game.component.Gold; -import toniarts.openkeeper.game.component.HauledBy; -import toniarts.openkeeper.game.component.Health; -import toniarts.openkeeper.game.component.InHand; -import toniarts.openkeeper.game.component.Interaction; -import toniarts.openkeeper.game.component.Mobile; -import toniarts.openkeeper.game.component.Navigation; -import toniarts.openkeeper.game.component.ObjectComponent; -import toniarts.openkeeper.game.component.ObjectViewState; -import toniarts.openkeeper.game.component.Objective; -import toniarts.openkeeper.game.component.Owner; -import toniarts.openkeeper.game.component.Party; -import toniarts.openkeeper.game.component.PlayerObjective; -import toniarts.openkeeper.game.component.PortalGem; -import toniarts.openkeeper.game.component.Position; -import toniarts.openkeeper.game.component.RoomStorage; -import toniarts.openkeeper.game.component.Senses; -import toniarts.openkeeper.game.component.Slapped; -import toniarts.openkeeper.game.component.Spellbook; -import toniarts.openkeeper.game.component.TaskComponent; -import toniarts.openkeeper.game.component.Threat; -import toniarts.openkeeper.game.component.TrapComponent; -import toniarts.openkeeper.game.component.TrapViewState; -import toniarts.openkeeper.game.component.Trigger; -import toniarts.openkeeper.game.component.ViewType; -import toniarts.openkeeper.game.controller.room.AbstractRoomController; -import toniarts.openkeeper.game.data.Keeper; -import toniarts.openkeeper.game.data.ObjectiveType; -import toniarts.openkeeper.game.data.PlayerSpell; -import toniarts.openkeeper.game.data.ResearchableEntity; -import toniarts.openkeeper.game.data.ResearchableType; -import toniarts.openkeeper.game.map.MapData; -import toniarts.openkeeper.game.map.MapTile; +import org.reflections.Reflections; import toniarts.openkeeper.game.network.chat.ChatHostedService; import toniarts.openkeeper.game.network.game.GameHostedService; import toniarts.openkeeper.game.network.lobby.LobbyHostedService; -import toniarts.openkeeper.game.network.message.GameData; -import toniarts.openkeeper.game.network.message.GameLoadProgressData; -import toniarts.openkeeper.game.network.message.StreamedMessage; import toniarts.openkeeper.game.network.session.AccountHostedService; import toniarts.openkeeper.game.network.streaming.StreamingHostedService; -import toniarts.openkeeper.game.state.lobby.ClientInfo; -import toniarts.openkeeper.game.task.TaskType; -import toniarts.openkeeper.tools.convert.map.Thing; -import toniarts.openkeeper.tools.convert.map.Tile; /** * @@ -123,84 +60,21 @@ public NetworkServer(String name, int port) throws UnknownHostException { this.port = port; } - private static void initialize() { + private static void initialize() throws InstantiationException, IllegalAccessException { if (!initialized) { initialized = true; - // Messages - Serializer.registerClass(StreamedMessage.class, new FieldSerializer()); - Serializer.registerClass(GameLoadProgressData.class, new FieldSerializer()); + Reflections reflections = new Reflections("toniarts.openkeeper"); - // Lobby - Serializer.registerClass(ClientInfo.class, new FieldSerializer()); - Serializer.registerClass(Keeper.class, new FieldSerializer()); + for (Class c : reflections.getTypesAnnotatedWith(Transferable.class)) { + Transferable a = c.getAnnotation(Transferable.class); + Serializer.registerClass(c, a.value().newInstance()); + } // Needed for the game Serializer.registerClass(Vector2f.class, new FieldSerializer()); Serializer.registerClass(Vector2.class, new FieldSerializer()); Serializer.registerClass(Point.class, new FieldSerializer()); - Serializer.registerClass(Tile.BridgeTerrainType.class, new EnumSerializer()); - Serializer.registerClass(Thing.HeroParty.Objective.class, new EnumSerializer()); - Serializer.registerClass(ObjectiveType.class, new EnumSerializer()); - Serializer.registerClass(MapData.class, new FieldSerializer()); // FIXME: Savable serializer would be better... - Serializer.registerClass(MapTile.class, new FieldSerializer()); - Serializer.registerClass(GameData.class, new FieldSerializer()); - //Serializer.registerClass(CreatureState.class, new EnumSerializer()); - Serializer.registerClass(AbstractRoomController.ObjectType.class, new EnumSerializer()); - Serializer.registerClass(ViewType.class, new EnumSerializer()); - Serializer.registerClass(TaskType.class, new EnumSerializer()); - Serializer.registerClass(ResearchableEntity.class, new FieldSerializer()); - Serializer.registerClass(PlayerSpell.class, new FieldSerializer()); - Serializer.registerClass(ResearchableType.class, new EnumSerializer()); - - // Our entity components - Serializer.registerClass(AttackTarget.class, new FieldSerializer()); - Serializer.registerClass(ChickenAi.class, new FieldSerializer()); - Serializer.registerClass(ChickenGenerator.class, new FieldSerializer()); - Serializer.registerClass(CreatureAi.class, new FieldSerializer()); - Serializer.registerClass(CreatureComponent.class, new FieldSerializer()); - Serializer.registerClass(CreatureEfficiency.class, new FieldSerializer()); - Serializer.registerClass(CreatureExperience.class, new FieldSerializer()); - Serializer.registerClass(CreatureFall.class, new FieldSerializer()); - Serializer.registerClass(CreatureHunger.class, new FieldSerializer()); - Serializer.registerClass(CreatureImprisoned.class, new FieldSerializer()); - Serializer.registerClass(CreatureMeleeAttack.class, new FieldSerializer()); - Serializer.registerClass(CreatureMood.class, new FieldSerializer()); - Serializer.registerClass(CreatureRecuperating.class, new FieldSerializer()); - Serializer.registerClass(CreatureSleep.class, new FieldSerializer()); - Serializer.registerClass(CreatureTortured.class, new FieldSerializer()); - Serializer.registerClass(CreatureViewState.class, new FieldSerializer()); - Serializer.registerClass(Death.class, new FieldSerializer()); - Serializer.registerClass(Decay.class, new FieldSerializer()); - Serializer.registerClass(DoorComponent.class, new FieldSerializer()); - Serializer.registerClass(DoorViewState.class, new FieldSerializer()); - Serializer.registerClass(Fearless.class, new FieldSerializer()); - Serializer.registerClass(FollowTarget.class, new FieldSerializer()); - Serializer.registerClass(Food.class, new FieldSerializer()); - Serializer.registerClass(Gold.class, new FieldSerializer()); - Serializer.registerClass(HauledBy.class, new FieldSerializer()); - Serializer.registerClass(Health.class, new FieldSerializer()); - Serializer.registerClass(InHand.class, new FieldSerializer()); - Serializer.registerClass(Interaction.class, new FieldSerializer()); - Serializer.registerClass(Mobile.class, new FieldSerializer()); - Serializer.registerClass(Navigation.class, new FieldSerializer()); - Serializer.registerClass(ObjectComponent.class, new FieldSerializer()); - Serializer.registerClass(ObjectViewState.class, new FieldSerializer()); - Serializer.registerClass(Objective.class, new FieldSerializer()); - Serializer.registerClass(Owner.class, new FieldSerializer()); - Serializer.registerClass(Party.class, new FieldSerializer()); - Serializer.registerClass(PlayerObjective.class, new FieldSerializer()); - Serializer.registerClass(PortalGem.class, new FieldSerializer()); - Serializer.registerClass(Position.class, new FieldSerializer()); - Serializer.registerClass(RoomStorage.class, new FieldSerializer()); - Serializer.registerClass(Senses.class, new FieldSerializer()); - Serializer.registerClass(Slapped.class, new FieldSerializer()); - Serializer.registerClass(Spellbook.class, new FieldSerializer()); - Serializer.registerClass(TaskComponent.class, new FieldSerializer()); - Serializer.registerClass(Threat.class, new FieldSerializer()); - Serializer.registerClass(TrapComponent.class, new FieldSerializer()); - Serializer.registerClass(TrapViewState.class, new FieldSerializer()); - Serializer.registerClass(Trigger.class, new FieldSerializer()); } } @@ -208,7 +82,7 @@ public T getService(Class type) { return server.getServices().getService(type); } - public void start() throws IOException { + public void start() throws IOException, InstantiationException, IllegalAccessException { if (server == null) { server = Network.createServer(NetworkConstants.GAME_NAME, NetworkConstants.PROTOCOL_VERSION, port, port); } diff --git a/src/toniarts/openkeeper/game/network/Transferable.java b/src/toniarts/openkeeper/game/network/Transferable.java new file mode 100644 index 000000000..e7f7f7b7c --- /dev/null +++ b/src/toniarts/openkeeper/game/network/Transferable.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2014-2020 OpenKeeper + * + * OpenKeeper is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * OpenKeeper is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with OpenKeeper. If not, see . + */ +package toniarts.openkeeper.game.network; + +import com.jme3.network.serializing.Serializer; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author ArchDemon + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface Transferable { + + Class value(); +} diff --git a/src/toniarts/openkeeper/game/network/game/GameClientService.java b/src/toniarts/openkeeper/game/network/game/GameClientService.java index 56e306bc1..a335c27b5 100644 --- a/src/toniarts/openkeeper/game/network/game/GameClientService.java +++ b/src/toniarts/openkeeper/game/network/game/GameClientService.java @@ -47,6 +47,7 @@ import toniarts.openkeeper.game.state.session.GameSessionClientService; import toniarts.openkeeper.game.state.session.GameSessionListener; import toniarts.openkeeper.tools.convert.map.TriggerAction; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Client side service for the game lobby services @@ -139,18 +140,18 @@ private GameSession getDelegate() { } @Override - public void selectTiles(Vector2f start, Vector2f end, boolean select) { - getDelegate().selectTiles(start, end, select); + public void selectTiles(SelectionArea area) { + getDelegate().selectTiles(area); } @Override - public void build(Vector2f start, Vector2f end, short roomId) { - getDelegate().build(start, end, roomId); + public void build(SelectionArea area, short roomId) { + getDelegate().build(area, roomId); } @Override - public void sell(Vector2f start, Vector2f end) { - getDelegate().sell(start, end); + public void sell(SelectionArea area) { + getDelegate().sell(area); } @Override diff --git a/src/toniarts/openkeeper/game/network/game/GameHostedService.java b/src/toniarts/openkeeper/game/network/game/GameHostedService.java index 6bfc5195f..28e5fe91a 100644 --- a/src/toniarts/openkeeper/game/network/game/GameHostedService.java +++ b/src/toniarts/openkeeper/game/network/game/GameHostedService.java @@ -55,6 +55,7 @@ import toniarts.openkeeper.game.state.session.GameSessionServiceListener; import toniarts.openkeeper.tools.convert.map.TriggerAction; import toniarts.openkeeper.utils.GameLoop; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Game server hosts lobby service for the game clients. @@ -516,23 +517,23 @@ public void markReady() { } @Override - public void selectTiles(Vector2f start, Vector2f end, boolean select) { + public void selectTiles(SelectionArea area) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onSelectTiles(start, end, select, clientInfo.getKeeper().getId()); + listener.onSelectTiles(area, clientInfo.getKeeper().getId()); } } @Override - public void build(Vector2f start, Vector2f end, short roomId) { + public void build(SelectionArea area, short roomId) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onBuild(start, end, roomId, clientInfo.getKeeper().getId()); + listener.onBuild(area, roomId, clientInfo.getKeeper().getId()); } } @Override - public void sell(Vector2f start, Vector2f end) { + public void sell(SelectionArea area) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onSell(start, end, clientInfo.getKeeper().getId()); + listener.onSell(area, clientInfo.getKeeper().getId()); } } diff --git a/src/toniarts/openkeeper/game/network/message/GameData.java b/src/toniarts/openkeeper/game/network/message/GameData.java index b51a0a539..9e7075038 100644 --- a/src/toniarts/openkeeper/game/network/message/GameData.java +++ b/src/toniarts/openkeeper/game/network/message/GameData.java @@ -16,15 +16,18 @@ */ package toniarts.openkeeper.game.network.message; +import com.jme3.network.serializing.serializers.FieldSerializer; import java.util.Collection; import toniarts.openkeeper.game.data.Keeper; import toniarts.openkeeper.game.map.MapData; +import toniarts.openkeeper.game.network.Transferable; /** * Wrapper for game data * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class GameData { private Collection players; diff --git a/src/toniarts/openkeeper/game/network/message/GameLoadProgressData.java b/src/toniarts/openkeeper/game/network/message/GameLoadProgressData.java index 334bc1da9..ad87ae2d6 100644 --- a/src/toniarts/openkeeper/game/network/message/GameLoadProgressData.java +++ b/src/toniarts/openkeeper/game/network/message/GameLoadProgressData.java @@ -17,12 +17,15 @@ package toniarts.openkeeper.game.network.message; import com.jme3.network.AbstractMessage; +import com.jme3.network.serializing.serializers.FieldSerializer; +import toniarts.openkeeper.game.network.Transferable; /** * The game loading progress data * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class GameLoadProgressData extends AbstractMessage { private short keeperId; diff --git a/src/toniarts/openkeeper/game/network/message/StreamedMessage.java b/src/toniarts/openkeeper/game/network/message/StreamedMessage.java index 43fb6fe75..345e87525 100644 --- a/src/toniarts/openkeeper/game/network/message/StreamedMessage.java +++ b/src/toniarts/openkeeper/game/network/message/StreamedMessage.java @@ -17,12 +17,15 @@ package toniarts.openkeeper.game.network.message; import com.jme3.network.AbstractMessage; +import com.jme3.network.serializing.serializers.FieldSerializer; +import toniarts.openkeeper.game.network.Transferable; /** * A message that holds a part (or all) of a streamed object data * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class StreamedMessage extends AbstractMessage { private int totalSize; diff --git a/src/toniarts/openkeeper/game/state/GameServerState.java b/src/toniarts/openkeeper/game/state/GameServerState.java index e4c06464f..bb3a934a8 100644 --- a/src/toniarts/openkeeper/game/state/GameServerState.java +++ b/src/toniarts/openkeeper/game/state/GameServerState.java @@ -46,6 +46,7 @@ import toniarts.openkeeper.tools.convert.map.Room; import toniarts.openkeeper.tools.convert.map.Trap; import toniarts.openkeeper.utils.Utils; +import toniarts.openkeeper.view.selection.SelectionArea; /** * The game state that actually runs the game. Has no relation to visuals. @@ -212,18 +213,18 @@ public GameSessionServiceListenerImpl() { } @Override - public void onSelectTiles(Vector2f start, Vector2f end, boolean select, short playerId) { - mapController.selectTiles(start, end, select, playerId); + public void onSelectTiles(SelectionArea area, short playerId) { + mapController.selectTiles(area, playerId); } @Override - public void onBuild(Vector2f start, Vector2f end, short roomId, short playerId) { - gameWorldController.build(start, end, playerId, roomId); + public void onBuild(SelectionArea area, short roomId, short playerId) { + gameWorldController.build(area, playerId, roomId); } @Override - public void onSell(Vector2f start, Vector2f end, short playerId) { - gameWorldController.sell(start, end, playerId); + public void onSell(SelectionArea area, short playerId) { + gameWorldController.sell(area, playerId); } @Override diff --git a/src/toniarts/openkeeper/game/state/lobby/ClientInfo.java b/src/toniarts/openkeeper/game/state/lobby/ClientInfo.java index 02931431c..8e70da2f0 100644 --- a/src/toniarts/openkeeper/game/state/lobby/ClientInfo.java +++ b/src/toniarts/openkeeper/game/state/lobby/ClientInfo.java @@ -16,13 +16,16 @@ */ package toniarts.openkeeper.game.state.lobby; +import com.jme3.network.serializing.serializers.FieldSerializer; import toniarts.openkeeper.game.data.Keeper; +import toniarts.openkeeper.game.network.Transferable; /** * Small container to hold info about the connected client * * @author Toni Helenius */ +@Transferable(FieldSerializer.class) public class ClientInfo { private int systemMemory; diff --git a/src/toniarts/openkeeper/game/state/session/GameSession.java b/src/toniarts/openkeeper/game/state/session/GameSession.java index 8ff5aa844..67f4d645f 100644 --- a/src/toniarts/openkeeper/game/state/session/GameSession.java +++ b/src/toniarts/openkeeper/game/state/session/GameSession.java @@ -22,6 +22,7 @@ import com.simsilica.es.EntityId; import java.awt.Point; import toniarts.openkeeper.game.state.CheatState; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Clients view on game service @@ -60,31 +61,27 @@ public interface GameSession { /** * Build a building to the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area * @param roomId room to build */ @Asynchronous - public void build(Vector2f start, Vector2f end, short roomId); + public void build(SelectionArea area, short roomId); /** * Sell building(s) from the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area */ @Asynchronous - public void sell(Vector2f start, Vector2f end); + public void sell(SelectionArea area); /** * Set some tiles selected/undelected * - * @param start start coordinates - * @param end end coordinates - * @param select select or unselect + * @param area */ @Asynchronous - public void selectTiles(Vector2f start, Vector2f end, boolean select); + public void selectTiles(SelectionArea area); /** * Interact with given entity diff --git a/src/toniarts/openkeeper/game/state/session/GameSessionServiceListener.java b/src/toniarts/openkeeper/game/state/session/GameSessionServiceListener.java index f063adf54..4db7acd16 100644 --- a/src/toniarts/openkeeper/game/state/session/GameSessionServiceListener.java +++ b/src/toniarts/openkeeper/game/state/session/GameSessionServiceListener.java @@ -21,6 +21,7 @@ import com.simsilica.es.EntityId; import java.awt.Point; import toniarts.openkeeper.game.state.CheatState; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Listener for the service. To listen to clients' requests @@ -32,34 +33,30 @@ public interface GameSessionServiceListener { /** * Build a building to the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area * @param roomId room to build * @param playerId the player who builds the room */ @Asynchronous - public void onBuild(Vector2f start, Vector2f end, short roomId, short playerId); + public void onBuild(SelectionArea area, short roomId, short playerId); /** * Sell building(s) from the wanted area * - * @param start start coordinates - * @param end end coordinates + * @param area * @param playerId the player who sells the tile */ @Asynchronous - public void onSell(Vector2f start, Vector2f end, short playerId); + public void onSell(SelectionArea area, short playerId); /** * Set some tiles selected/undelected * - * @param start start coordinates - * @param end end coordinates - * @param select select or unselect + * @param area * @param playerId the player who selected the tile */ @Asynchronous - public void onSelectTiles(Vector2f start, Vector2f end, boolean select, short playerId); + public void onSelectTiles(SelectionArea area, short playerId); /** * Player wants to interact with an entity diff --git a/src/toniarts/openkeeper/game/state/session/LocalGameSession.java b/src/toniarts/openkeeper/game/state/session/LocalGameSession.java index e852c2138..586fd4737 100644 --- a/src/toniarts/openkeeper/game/state/session/LocalGameSession.java +++ b/src/toniarts/openkeeper/game/state/session/LocalGameSession.java @@ -40,6 +40,7 @@ import toniarts.openkeeper.tools.convert.map.TriggerAction; import toniarts.openkeeper.utils.PathUtils; import toniarts.openkeeper.utils.Utils; +import toniarts.openkeeper.view.selection.SelectionArea; /** * Local game session, a virtual server @@ -282,23 +283,23 @@ public void loadStatus(float progress) { } @Override - public void selectTiles(Vector2f start, Vector2f end, boolean select) { + public void selectTiles(SelectionArea area) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onSelectTiles(start, end, select, PLAYER_ID); + listener.onSelectTiles(area, PLAYER_ID); } } @Override - public void build(Vector2f start, Vector2f end, short roomId) { + public void build(SelectionArea area, short roomId) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onBuild(start, end, roomId, PLAYER_ID); + listener.onBuild(area, roomId, PLAYER_ID); } } @Override - public void sell(Vector2f start, Vector2f end) { + public void sell(SelectionArea area) { for (GameSessionServiceListener listener : serverListeners.getArray()) { - listener.onSell(start, end, PLAYER_ID); + listener.onSell(area, PLAYER_ID); } } diff --git a/src/toniarts/openkeeper/game/task/TaskManager.java b/src/toniarts/openkeeper/game/task/TaskManager.java index ddbad1e8d..8685be9d0 100644 --- a/src/toniarts/openkeeper/game/task/TaskManager.java +++ b/src/toniarts/openkeeper/game/task/TaskManager.java @@ -391,13 +391,9 @@ private void scanBridgeSurroundings(List tiles) { } private void scanInitialTasks() { - MapData mapData = mapController.getMapData(); - for (int y = 0; y < mapData.getHeight(); y++) { - for (int x = 0; x < mapData.getWidth(); x++) { - scanTerrainTasks(mapController.getMapData().getTile(x, y), false, false); - } + for (MapTile tile : mapController.getMapData()) { + scanTerrainTasks(tile, false, false); } - // Object tasks // for (ObjectControl objectControl : worldState.getThingLoader().getObjects()) { // for (Entry> entry : taskQueues.entrySet()) { diff --git a/src/toniarts/openkeeper/game/task/TaskType.java b/src/toniarts/openkeeper/game/task/TaskType.java index 1ae5bb2dc..9d551ec12 100644 --- a/src/toniarts/openkeeper/game/task/TaskType.java +++ b/src/toniarts/openkeeper/game/task/TaskType.java @@ -16,11 +16,15 @@ */ package toniarts.openkeeper.game.task; +import com.jme3.network.serializing.serializers.EnumSerializer; +import toniarts.openkeeper.game.network.Transferable; + /** * Type of task * * @author Toni Helenius */ +@Transferable(EnumSerializer.class) public enum TaskType { CLAIM_LAIR, diff --git a/src/toniarts/openkeeper/game/trigger/actionpoint/ActionPointTriggerControl.java b/src/toniarts/openkeeper/game/trigger/actionpoint/ActionPointTriggerControl.java index 913a87289..9b73680ea 100644 --- a/src/toniarts/openkeeper/game/trigger/actionpoint/ActionPointTriggerControl.java +++ b/src/toniarts/openkeeper/game/trigger/actionpoint/ActionPointTriggerControl.java @@ -16,6 +16,7 @@ */ package toniarts.openkeeper.game.trigger.actionpoint; +import java.awt.Point; import java.util.logging.Level; import java.util.logging.Logger; import toniarts.openkeeper.game.controller.ICreaturesController; @@ -72,12 +73,10 @@ protected boolean isActive(TriggerGenericData trigger) { switch (type) { case 0: case 3: // Creature - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - for (ICreatureController creature : entityPositionLookup.getEntityTypesInLocation(x, y, ICreatureController.class)) { - if ((playerId == 0 || creature.getOwnerId() == playerId) && (targetId == 0 || creature.getCreature().getCreatureId() == targetId)) { - target++; - } + for (Point p : ap) { + for (ICreatureController creature : entityPositionLookup.getEntityTypesInLocation(p, ICreatureController.class)) { + if ((playerId == 0 || creature.getOwnerId() == playerId) && (targetId == 0 || creature.getCreature().getCreatureId() == targetId)) { + target++; } } } @@ -112,11 +111,9 @@ protected boolean isActive(TriggerGenericData trigger) { value = trigger.getUserData("value", int.class); MapData map = mapController.getMapData(); - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - if (playerId == map.getTile(x, y).getOwnerId()) { - target++; - } + for (Point p : ap) { + if (playerId == map.getTile(p).getOwnerId()) { + target++; } } break; @@ -125,11 +122,9 @@ protected boolean isActive(TriggerGenericData trigger) { playerId = trigger.getUserData("playerId", short.class); // value = trigger.getUserData("value", int.class); // Unusefull ? map = mapController.getMapData(); - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - if (playerId != map.getTile(x, y).getOwnerId()) { - return false; - } + for (Point p : ap) { + if (playerId != map.getTile(p).getOwnerId()) { + return false; } } return true; @@ -140,16 +135,15 @@ protected boolean isActive(TriggerGenericData trigger) { value = trigger.getUserData("value", int.class); map = mapController.getMapData(); - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - MapTile tile = map.getTile(x, y); + for (Point p : ap) { + MapTile tile = map.getTile(p); - if (playerId != 0 && playerId != tile.getOwnerId() || targetId != tile.getTerrainId()) { - continue; - } - - target++; + if (playerId != 0 && playerId != tile.getOwnerId() || targetId != tile.getTerrainId()) { + continue; } + + target++; + } break; @@ -158,12 +152,9 @@ protected boolean isActive(TriggerGenericData trigger) { value = trigger.getUserData("value", int.class); map = mapController.getMapData(); - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - // TODO check who tagged tile - if (map.getTile(x, y).isSelected(playerId)) { - target++; - } + for (Point p : ap) { + if (map.getTile(p).isSelected(playerId)) { + target++; } } break; @@ -172,12 +163,9 @@ protected boolean isActive(TriggerGenericData trigger) { playerId = trigger.getUserData("playerId", short.class); // value = trigger.getUserData("value", int.class); // Unusefull ? map = mapController.getMapData(); - for (int x = (int) ap.getStart().x; x <= (int) ap.getEnd().x; x++) { - for (int y = (int) ap.getStart().y; y <= (int) ap.getEnd().y; y++) { - // TODO check who tagged tile - if (!map.getTile(x, y).isSelected(playerId)) { - return false; - } + for (Point p : ap) { + if (!map.getTile(p).isSelected(playerId)) { + return false; } } return true; diff --git a/src/toniarts/openkeeper/tools/convert/map/Thing.java b/src/toniarts/openkeeper/tools/convert/map/Thing.java index 96006d553..3d1d78217 100644 --- a/src/toniarts/openkeeper/tools/convert/map/Thing.java +++ b/src/toniarts/openkeeper/tools/convert/map/Thing.java @@ -16,11 +16,13 @@ */ package toniarts.openkeeper.tools.convert.map; +import com.jme3.network.serializing.serializers.EnumSerializer; import java.util.EnumSet; import java.util.List; import javax.vecmath.Vector3f; import toniarts.openkeeper.game.data.IIndexable; import toniarts.openkeeper.game.data.ITriggerable; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.IFlagEnum; import toniarts.openkeeper.tools.convert.IValueEnum; import toniarts.openkeeper.tools.convert.map.Thing.HeroParty.Objective; @@ -716,6 +718,7 @@ public static class HeroParty extends Thing implements Comparable, IT * unify these, just add a boolean whether it is available to parties * only */ + @Transferable(EnumSerializer.class) public enum Objective implements IValueEnum { NONE(0), diff --git a/src/toniarts/openkeeper/tools/convert/map/Tile.java b/src/toniarts/openkeeper/tools/convert/map/Tile.java index 502945b46..1161385d3 100644 --- a/src/toniarts/openkeeper/tools/convert/map/Tile.java +++ b/src/toniarts/openkeeper/tools/convert/map/Tile.java @@ -16,6 +16,8 @@ */ package toniarts.openkeeper.tools.convert.map; +import com.jme3.network.serializing.serializers.EnumSerializer; +import toniarts.openkeeper.game.network.Transferable; import toniarts.openkeeper.tools.convert.IValueEnum; /** @@ -28,6 +30,7 @@ */ public class Tile { + @Transferable(EnumSerializer.class) public enum BridgeTerrainType implements IValueEnum { WATER(1), LAVA(2); diff --git a/src/toniarts/openkeeper/view/PlayerCameraState.java b/src/toniarts/openkeeper/view/PlayerCameraState.java index 31d33673c..079b49fe5 100644 --- a/src/toniarts/openkeeper/view/PlayerCameraState.java +++ b/src/toniarts/openkeeper/view/PlayerCameraState.java @@ -224,6 +224,7 @@ public void doTransition(int sweepFileId, final Vector3f start, final CinematicE String sweepFile = "EnginePath" + sweepFileId; // Do cinematic transition + // FIXME app is null sometimes. Maybe State not initialized yet Cinematic c = new Cinematic(app, sweepFile, start); c.addListener(new CinematicEventListener() { @Override diff --git a/src/toniarts/openkeeper/view/PlayerInteractionState.java b/src/toniarts/openkeeper/view/PlayerInteractionState.java index 7f2e419db..6b3f3cebf 100644 --- a/src/toniarts/openkeeper/view/PlayerInteractionState.java +++ b/src/toniarts/openkeeper/view/PlayerInteractionState.java @@ -41,6 +41,7 @@ import de.lessvoid.nifty.elements.Element; import java.awt.Point; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; import java.util.logging.Logger; import toniarts.openkeeper.Main; @@ -190,38 +191,41 @@ protected SelectionHandler.ColorIndicator getColorIndicator() { } return ColorIndicator.RED; } - if (interactionState.getType() == Type.SELL) { + if (interactionState.getType() == Type.SELL + && !gameClientState.getMapClientService().isSellable(selectionHandler.getSelectionArea(), player.getPlayerId())) { return ColorIndicator.RED; - } else if (interactionState.getType() == Type.ROOM + } + if (interactionState.getType() == Type.ROOM && !(gameClientState.getMapClientService().isTaggable(p) - || (gameClientState.getMapClientService().isBuildable(p, player.getPlayerId(), (short) interactionState.getItemId()) - && isPlayerAffordToBuild(player, gameClientState.getLevelData().getRoomById(interactionState.getItemId()))))) { + || isPlayerAffordToBuild(selectionHandler.getSelectionArea(), player.getPlayerId(), (short) interactionState.getItemId()))) { return ColorIndicator.RED; } return ColorIndicator.BLUE; } - private boolean isPlayerAffordToBuild(Player player, Room room) { - int playerMoney = gameClientState.getPlayer(player.getPlayerId()).getGold(); + private boolean isPlayerAffordToBuild(SelectionArea area, short playerId, short roomId) { + int playerMoney = gameClientState.getPlayer(playerId).getGold(); + Room room = gameClientState.getLevelData().getRoomById(roomId); if (playerMoney == 0) { return false; } + if (!gameClientState.getMapClientService().isBuildable(area, playerId, roomId)) { + return false; + } int buildablePlots = 0; - for (int x = (int) Math.max(0, selectionHandler.getSelectionArea().getStart().x); x < Math.min(gameClientState.getMapClientService().getMapData().getWidth(), selectionHandler.getSelectionArea().getEnd().x + 1); x++) { - for (int y = (int) Math.max(0, selectionHandler.getSelectionArea().getStart().y); y < Math.min(gameClientState.getMapClientService().getMapData().getHeight(), selectionHandler.getSelectionArea().getEnd().y + 1); y++) { - Point p = new Point(x, y); + for (Iterator it = area.simpleIterator(); it.hasNext();) { + Point p = it.next(); - if (gameClientState.getMapClientService().isBuildable(p, player.getPlayerId(), room.getId())) { - buildablePlots++; - } + if (gameClientState.getMapClientService().isBuildable(p, playerId, roomId)) { + buildablePlots++; + } - // See the gold amount - if (playerMoney < buildablePlots * room.getCost()) { - return false; - } + // See the gold amount + if (playerMoney < buildablePlots * room.getCost()) { + return false; } } - return true; + return (buildablePlots != 0); } }; @@ -598,14 +602,13 @@ public void onMouseButtonEvent(MouseButtonEvent evt) { || (interactionState.getType() == Type.ROOM && gameClientState.getMapClientService().isTaggable(WorldUtils.vectorToPoint(selectionArea.getRealStart())))) { - // Determine if this is a select/deselect by the starting tile's status - boolean select = !gameClientState.getMapClientService().isSelected(WorldUtils.vectorToPoint(selectionArea.getRealStart()), player.getPlayerId()); - gameClientState.getGameClientService().selectTiles(selectionArea.getStart(), selectionArea.getEnd(), select); + gameClientState.getGameClientService().selectTiles(selectionArea); } else if (interactionState.getType() == Type.ROOM - && gameClientState.getMapClientService().isBuildable(WorldUtils.vectorToPoint(selectionArea.getRealStart()), player.getPlayerId(), (short) interactionState.getItemId())) { - gameClientState.getGameClientService().build(selectionArea.getStart(), selectionArea.getEnd(), (short) interactionState.getItemId()); - } else if (interactionState.getType() == Type.SELL) { - gameClientState.getGameClientService().sell(selectionArea.getStart(), selectionArea.getEnd()); + && gameClientState.getMapClientService().isBuildable(selectionArea, player.getPlayerId(), (short) interactionState.getItemId())) { + gameClientState.getGameClientService().build(selectionArea, (short) interactionState.getItemId()); + } else if (interactionState.getType() == Type.SELL + && gameClientState.getMapClientService().isSellable(selectionArea, player.getPlayerId())) { + gameClientState.getGameClientService().sell(selectionArea); } selectionHandler.setActive(false); diff --git a/src/toniarts/openkeeper/view/selection/SelectionArea.java b/src/toniarts/openkeeper/view/selection/SelectionArea.java index 5d7dc2022..21dca790e 100644 --- a/src/toniarts/openkeeper/view/selection/SelectionArea.java +++ b/src/toniarts/openkeeper/view/selection/SelectionArea.java @@ -1,45 +1,34 @@ package toniarts.openkeeper.view.selection; +import com.jme3.math.FastMath; import com.jme3.math.Vector2f; import java.awt.Point; -import java.util.ArrayList; +import java.util.HashSet; import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; +import java.util.Set; import java.util.function.Consumer; import toniarts.openkeeper.utils.WorldUtils; /** * @author 7willuwe : Philip Willuweit */ -public class SelectionArea implements Iterable> { +public class SelectionArea implements Iterable> { private Vector2f start = new Vector2f(); private Vector2f end = new Vector2f(); - private float scale = 1; - public SelectionArea(Vector2f start, Vector2f end) { - this.start = start; - this.end = end; - } - - public SelectionArea(float appScaled) { - this.scale = appScaled; + public SelectionArea() { this.start = new Vector2f(Vector2f.ZERO); this.end = new Vector2f(Vector2f.ZERO); } /** - * For single square use only - * - * @param appScaled * @param start Start position * @param end End position */ - public SelectionArea(float appScaled, Vector2f start, Vector2f end) { + public SelectionArea(Vector2f start, Vector2f end) { this.start = start; this.end = end; - this.scale = appScaled; } /** @@ -89,20 +78,6 @@ public void setEnd(Vector2f position) { end.set(position); } - /** - * @return the scale - */ - public float getScale() { - return scale; - } - - /** - * @param scale the scale to set - */ - public void setScale(float scale) { - this.scale = scale; - } - public Vector2f getCenter() { return new Vector2f((end.x + start.x) / 2, (start.y + end.y) / 2); } @@ -111,62 +86,108 @@ public Vector2f getCenter() { * @return the delta x axis */ public float getDeltaX() { - return (Math.abs(end.x - start.x) + 1) / scale; + return (Math.abs(end.x - start.x) + 1); } /** * @return the delta y axis */ public float getDeltaY() { - return (Math.abs(end.y - start.y) + 1) / scale; + return (Math.abs(end.y - start.y) + 1); } @Override - public Iterator> iterator() { + public Iterator> iterator() { return new SelectionArea.AreaIterator(); } - /** - * An optimized version of AbstractList.Itr - */ - private class AreaIterator implements Iterator> { + public Iterator simpleIterator() { + return new SimpleIterator(); + } + + private class SimpleIterator implements Iterator { - private final Point cursor = WorldUtils.vectorToPoint(SelectionArea.this.getStart()); private final Point start = WorldUtils.vectorToPoint(SelectionArea.this.getStart()); private final Point end = WorldUtils.vectorToPoint(SelectionArea.this.getEnd()); + private Point cursor; @Override public boolean hasNext() { - return cursor.x != (end.x + 1) && cursor.y != (end.y + 1); + return !end.equals(cursor); } @Override - public List next() { - List result = new ArrayList<>(); + public Point next() { - while (cursor.y >= start.y && cursor.x <= end.x) { - check(); - result.add(new Point(cursor.x, cursor.y)); - - cursor.x++; - cursor.y--; + if (cursor == null) { + cursor = (Point) start.clone(); + return cursor; } - if (cursor.y < start.y) { - cursor.y = start.y + (cursor.x - start.x); + cursor.x++; + if (cursor.x > end.x) { cursor.x = start.x; + cursor.y++; } - if (cursor.x > end.x) { - cursor.y += (cursor.x - start.x) + 1; - cursor.x = start.x; + return cursor; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public void forEachRemaining(Consumer consumer) { + throw new UnsupportedOperationException(); + } + } + + /** + * An optimized version of AbstractList.Itr + */ + private class AreaIterator implements Iterator> { + + private final Point start = WorldUtils.vectorToPoint(SelectionArea.this.getStart()); + private final Point end = WorldUtils.vectorToPoint(SelectionArea.this.getEnd()); + private final Point realStart = WorldUtils.vectorToPoint(SelectionArea.this.getRealStart()); + private final Point realEnd = WorldUtils.vectorToPoint(SelectionArea.this.getRealEnd()); + private final Point delta = new Point(FastMath.sign(realStart.x - realEnd.x), + FastMath.sign(realStart.y - realEnd.y)); + + private Set cursor = new HashSet<>(); + + @Override + public boolean hasNext() { + return !(cursor.size() == 1 && cursor.contains(realStart)); + } + + @Override + public Set next() { + Set result = new HashSet<>(); + + if (cursor.isEmpty()) { + result.add(realEnd); } - if (cursor.y > end.y) { - cursor.x = start.x + (cursor.y - end.y); - cursor.y = end.y; + for (Point p : cursor) { + if (delta.x != 0) { + Point neighborhood = new Point(p.x + delta.x, p.y); + if (check(neighborhood)) { + result.add(neighborhood); + } + } + if (delta.y != 0) { + Point neighborhood = new Point(p.x, p.y + delta.y); + if (check(neighborhood)) { + result.add(neighborhood); + } + } } + cursor = result; + return result; } @@ -176,15 +197,12 @@ public void remove() { } @Override - public void forEachRemaining(Consumer> consumer) { + public void forEachRemaining(Consumer> consumer) { throw new UnsupportedOperationException(); } - private void check() { - if (cursor.x > end.x || cursor.x < start.x - || cursor.y > end.y || cursor.y < start.y) { - throw new NoSuchElementException(); - } + private boolean check(Point p) { + return p.x <= end.x && p.x >= start.x && p.y <= end.y && p.y >= start.y; } } } diff --git a/src/toniarts/openkeeper/view/selection/SelectionHandler.java b/src/toniarts/openkeeper/view/selection/SelectionHandler.java index 4c580add4..3d1b47a7b 100644 --- a/src/toniarts/openkeeper/view/selection/SelectionHandler.java +++ b/src/toniarts/openkeeper/view/selection/SelectionHandler.java @@ -55,7 +55,7 @@ public ColorRGBA getColor() { public SelectionHandler(Main app) { this.app = app; - this.selectionArea = new SelectionArea(MapLoader.TILE_WIDTH); + this.selectionArea = new SelectionArea(); setupVisualsForSelection(); } @@ -74,11 +74,11 @@ public boolean update(Vector2f mousePosition) { Vector3f tmp = cam.getWorldCoordinates(this.mousePosition, 0f).clone(); Vector3f dir = cam.getWorldCoordinates(this.mousePosition, 1f).subtractLocal(tmp).normalizeLocal(); dir.multLocal((MapLoader.TOP_HEIGHT - pos.getY()) / dir.getY()).addLocal(pos); - + pointedPosition.set(dir.getX(), dir.getZ()); pointedTileIndex = WorldUtils.vectorToPoint(pointedPosition); pointedTilePosition = WorldUtils.pointToVector2f(pointedTileIndex); - + setPos(pointedTilePosition); return true; @@ -101,7 +101,7 @@ public Vector2f getActualPointedPosition() { public Point getPointedTileIndex() { return pointedTileIndex; } - + /** * Show coordinate of tile pointed by mouse *