diff --git a/assets/Data/units/units.json b/assets/Data/units/units.json new file mode 100644 index 00000000..55b42792 --- /dev/null +++ b/assets/Data/units/units.json @@ -0,0 +1,19 @@ +{ + "units": [ + { + "id" : "humanBlocker", + "creatureId" : "human", + "equipment" : [ + { + "pointId" : "handsCombined", + "itemId" : "Katana2H" + } + ], + "ai" : [ + { + "name" : "Blocker" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/java/electrosphere/game/data/Config.java b/src/main/java/electrosphere/game/data/Config.java index 3a9699fd..cb6e817e 100644 --- a/src/main/java/electrosphere/game/data/Config.java +++ b/src/main/java/electrosphere/game/data/Config.java @@ -17,6 +17,8 @@ import electrosphere.game.data.particle.ParticleDefinition; import electrosphere.game.data.projectile.ProjectileTypeHolder; import electrosphere.game.data.structure.type.model.StructureTypeMap; import electrosphere.game.data.tutorial.HintDefinition; +import electrosphere.game.data.units.UnitDefinitionFile; +import electrosphere.game.data.units.UnitLoader; import electrosphere.game.data.voxel.VoxelData; import electrosphere.game.server.race.model.RaceMap; import electrosphere.game.server.symbolism.model.SymbolMap; @@ -51,6 +53,11 @@ public class Config { * The particle definition */ ParticleDefinition particleDefinition; + + /** + * The unit loader + */ + UnitLoader unitLoader; /** * Loads the default data @@ -71,6 +78,7 @@ public class Config { config.surfaceAudioCollection = FileUtils.loadObjectFromAssetPath("Data/audio/surface.json", SurfaceAudioCollection.class); config.particleDefinition = FileUtils.loadObjectFromAssetPath("Data/particles.json", ParticleDefinition.class); config.projectileTypeHolder.init(); + config.unitLoader = UnitLoader.create(FileUtils.loadObjectFromAssetPath("Data/units/units.json", UnitDefinitionFile.class)); //validate ConfigValidator.valdiate(config); @@ -255,5 +263,13 @@ public class Config { public ParticleDefinition getParticleDefinition(){ return particleDefinition; } + + /** + * Gets the unit loader + * @return The unit loader + */ + public UnitLoader getUnitLoader(){ + return unitLoader; + } } diff --git a/src/main/java/electrosphere/game/data/units/UnitDefinition.java b/src/main/java/electrosphere/game/data/units/UnitDefinition.java new file mode 100644 index 00000000..827f5bed --- /dev/null +++ b/src/main/java/electrosphere/game/data/units/UnitDefinition.java @@ -0,0 +1,64 @@ +package electrosphere.game.data.units; + +import java.util.List; + +import electrosphere.game.data.creature.type.ai.AITreeData; + +/** + * A creature associated with some equipment and AI + */ +public class UnitDefinition { + + /** + * The name of the unit + */ + String id; + + /** + * The creature that is the base of this unit + */ + String creatureId; + + /** + * The ai trees associated with this unit + */ + List ai; + + /** + * The items equipped to the unit + */ + List equipment; + + /** + * Gets the id of the unit + * @return The id + */ + public String getId(){ + return id; + } + + /** + * Gets the id of the creature associated with the unit + * @return The id of the creature + */ + public String getCreatureId(){ + return creatureId; + } + + /** + * Gets the AI associated with the unit + * @return The ai + */ + public List getAI(){ + return ai; + } + + /** + * Gets the equipment attached to the unit + * @return The equipment + */ + public List getEquipment(){ + return equipment; + } + +} diff --git a/src/main/java/electrosphere/game/data/units/UnitDefinitionFile.java b/src/main/java/electrosphere/game/data/units/UnitDefinitionFile.java new file mode 100644 index 00000000..772d2020 --- /dev/null +++ b/src/main/java/electrosphere/game/data/units/UnitDefinitionFile.java @@ -0,0 +1,23 @@ +package electrosphere.game.data.units; + +import java.util.List; + +/** + * A file defining a whole bunch of units + */ +public class UnitDefinitionFile { + + /** + * The unit definitions contained in this file + */ + List units; + + /** + * Gets the units contained in this file + * @return The list of units + */ + public List getUnits(){ + return units; + } + +} diff --git a/src/main/java/electrosphere/game/data/units/UnitEquippedItem.java b/src/main/java/electrosphere/game/data/units/UnitEquippedItem.java new file mode 100644 index 00000000..8491a7c3 --- /dev/null +++ b/src/main/java/electrosphere/game/data/units/UnitEquippedItem.java @@ -0,0 +1,34 @@ +package electrosphere.game.data.units; + +/** + * An item equipped to a unit + */ +public class UnitEquippedItem { + + /** + * The equip point that has an item equipped + */ + String pointId; + + /** + * The id of the item attached to the point + */ + String itemId; + + /** + * Gets the equip point that has an item attached + * @return The equip point + */ + public String getPointId(){ + return pointId; + } + + /** + * Gets the id of the item equipped to the point + * @return The id of the item + */ + public String getItemId(){ + return itemId; + } + +} diff --git a/src/main/java/electrosphere/game/data/units/UnitLoader.java b/src/main/java/electrosphere/game/data/units/UnitLoader.java new file mode 100644 index 00000000..140df99a --- /dev/null +++ b/src/main/java/electrosphere/game/data/units/UnitLoader.java @@ -0,0 +1,55 @@ +package electrosphere.game.data.units; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * Loads the unit definition and provides utilities for extracting specific units + */ +public class UnitLoader { + + /** + * Map of unit id -> unit data + */ + Map unitMap = new HashMap(); + + /** + * Creates a unit loader from a raw definition file + * @param rawData The raw file + * @return The unit loader + */ + public static UnitLoader create(UnitDefinitionFile rawData){ + UnitLoader rVal = new UnitLoader(); + for(UnitDefinition unit : rawData.getUnits()){ + rVal.putUnit(unit); + } + return rVal; + } + + /** + * Adds a unit to the loader + * @param unit The unit + */ + public void putUnit(UnitDefinition unit){ + unitMap.put(unit.getId(),unit); + } + + /** + * Gets a unit by its id + * @param unitId The id of the unit + * @return The unit if it exists, null otherwise + */ + public UnitDefinition getUnit(String unitId){ + return unitMap.get(unitId); + } + + /** + * Gets the collection of all units + * @return The collection of all units + */ + public Collection getUnits(){ + return unitMap.values(); + } + +} diff --git a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsLevelEditor.java b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsLevelEditor.java index 2801c16f..5f2fbcc7 100644 --- a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsLevelEditor.java +++ b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsLevelEditor.java @@ -18,6 +18,7 @@ import electrosphere.game.data.creature.type.CreatureData; import electrosphere.game.data.foliage.type.FoliageType; import electrosphere.game.data.item.type.Item; import electrosphere.game.data.object.type.ObjectData; +import electrosphere.game.data.units.UnitDefinition; import electrosphere.logger.LoggerInterface; import electrosphere.menu.WindowStrings; import electrosphere.menu.WindowUtils; @@ -36,6 +37,7 @@ import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaFlexDirection import electrosphere.renderer.ui.elementtypes.ContainerElement.YogaJustification; import electrosphere.renderer.ui.events.NavigationEvent; import electrosphere.renderer.ui.events.ValueChangeEvent; +import electrosphere.server.content.unit.UnitUtils; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.utils.EntityLookupUtils; @@ -105,6 +107,11 @@ public class MenuGeneratorsLevelEditor { fillInSpawnCreatureContent(scrollable); })); + //spawn unit button + scrollable.addChild(Button.createButton("Spawn Unit", () -> { + fillInSpawnUnitContent(scrollable); + })); + //spawn foliage button scrollable.addChild(Button.createButton("Spawn Foliage", () -> { fillInSpawnFoliageContent(scrollable); @@ -175,6 +182,35 @@ public class MenuGeneratorsLevelEditor { Globals.signalSystem.post(SignalType.YOGA_APPLY,mainSidePanel); } + /** + * Fills in the content for spawning units + * @param scrollable + */ + private static void fillInSpawnUnitContent(VirtualScrollable scrollable){ + + scrollable.clearChildren(); + + //back button + scrollable.addChild(Button.createButton("Back", () -> { + fillInDefaultContent(scrollable); + })); + + //button for spawning all creatures + for(UnitDefinition unitDefinition : Globals.gameConfigCurrent.getUnitLoader().getUnits()){ + //spawn creature button + scrollable.addChild(Button.createButton("Spawn " + unitDefinition.getId(), () -> { + LoggerInterface.loggerEngine.INFO("spawn " + unitDefinition.getId() + "!"); + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(Globals.playerCamera)); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + Vector3d cursorPos = realm.getCollisionEngine().rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), 5.0).add(cursorVerticalOffset); + UnitUtils.spawnUnit(realm, cursorPos, unitDefinition.getId()); + })); + } + + Globals.signalSystem.post(SignalType.YOGA_APPLY,mainSidePanel); + } + /** * Level editor content for spawning foliage * @param scrollable diff --git a/src/main/java/electrosphere/server/content/unit/UnitUtils.java b/src/main/java/electrosphere/server/content/unit/UnitUtils.java new file mode 100644 index 00000000..dd37a216 --- /dev/null +++ b/src/main/java/electrosphere/server/content/unit/UnitUtils.java @@ -0,0 +1,74 @@ +package electrosphere.server.content.unit; + +import org.joml.Vector3d; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.state.equip.ServerEquipState; +import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.types.creature.CreatureTemplate; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.units.UnitDefinition; +import electrosphere.game.data.units.UnitEquippedItem; +import electrosphere.game.data.units.UnitLoader; +import electrosphere.logger.LoggerInterface; +import electrosphere.server.datacell.Realm; + +/** + * Utilities for dealing with units + */ +public class UnitUtils { + + /** + * Spawns a unit + * @param realm The realm to spawn in + * @param position The position to spawn at + * @param type The type of unit + * @return The entity encompassing the unit + */ + public static Entity spawnUnit(Realm realm, Vector3d position, String type){ + UnitLoader unitLoader = Globals.gameConfigCurrent.getUnitLoader(); + UnitDefinition unitDefinition = unitLoader.getUnit(type); + if(unitDefinition == null){ + LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Tried to spawn undefined unit type! " + type)); + return null; + } + String creatureId = unitDefinition.getCreatureId(); + if(creatureId == null || creatureId.equals("")){ + LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Tried to spawn unit with invalid creatureId! \"" + creatureId + "\"")); + return null; + } + Entity rVal = CreatureUtils.serverSpawnBasicCreature(realm, position, creatureId, CreatureTemplate.createDefault(creatureId)); + + //optionally apply ai + if(unitDefinition.getAI() != null){ + Globals.aiManager.removeAI(rVal); + Globals.aiManager.attachAI(rVal, unitDefinition.getAI()); + } + + //optionally add equipment + if(unitDefinition.getEquipment() != null){ + for(UnitEquippedItem equippedItem : unitDefinition.getEquipment()){ + if(equippedItem.getItemId() == null || equippedItem.getItemId().equals("")){ + LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Equipped item id is invalid! \"" + equippedItem.getItemId() + "\"")); + } + if(equippedItem.getPointId() == null || equippedItem.getPointId().equals("")){ + LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Equipped point id is invalid! \"" + equippedItem.getPointId() + "\"")); + } + //spawn the item in the world + Entity itemInWorld = ItemUtils.serverSpawnBasicItem(realm, position, equippedItem.getItemId()); + + //add the item to the creature's inventory + Entity itemInInventory = InventoryUtils.serverAttemptStoreItem(rVal, itemInWorld); + + //equip the item to the slot defined in the template + ServerEquipState serverEquipState = ServerEquipState.getEquipState(rVal); + serverEquipState.commandAttemptEquip(itemInInventory,serverEquipState.getEquipPoint(equippedItem.getPointId())); + } + } + + return rVal; + } + +}