Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added genomes to Edible Flora #5

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion module.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
{ "id": "CoreWorlds", "minVersion": "1.1.0" },
{ "id": "Hunger", "minVersion": "1.1.0" },
{ "id": "SimpleFarming", "minVersion": "2.1.0" },
{ "id": "Thirst", "minVersion": "1.0.0" }
{ "id": "Thirst", "minVersion": "1.0.0" },
{ "id": "Genome", "minVersion": "1.0.0" }
],
"serverSideOnly": false,
"isAsset": true
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/org/terasology/edibleFlora/events/OnSpawn.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright 2020 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.edibleFlora.events;

import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.Event;
import org.terasology.protobuf.EntityData;

public class OnSpawn implements Event {
private EntityRef bush;

public OnSpawn(EntityRef bush) {
this.bush = bush;
}

public EntityRef getBush() {
return bush;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright 2020 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.edibleFlora.genome;

import com.google.common.base.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.ReceiveEvent;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.genome.GenomeDefinition;
import org.terasology.genome.GenomeRegistry;
import org.terasology.genome.breed.BreedingAlgorithm;
import org.terasology.genome.breed.ContinuousBreedingAlgorithm;
import org.terasology.genome.breed.mutator.GeneMutator;
import org.terasology.genome.breed.mutator.VocabularyGeneMutator;
import org.terasology.genome.component.GenomeComponent;
import org.terasology.genome.genomeMap.SeedBasedGenomeMap;
import org.terasology.logic.characters.CharacterHeldItemComponent;
import org.terasology.logic.common.ActivateEvent;
import org.terasology.logic.common.RetainComponentsComponent;
import org.terasology.logic.console.commandSystem.annotations.Command;
import org.terasology.logic.console.commandSystem.annotations.Sender;
import org.terasology.logic.delay.DelayedActionTriggeredEvent;
import org.terasology.network.ClientComponent;
import org.terasology.registry.In;
import org.terasology.simpleFarming.components.BushDefinitionComponent;
import org.terasology.simpleFarming.components.BushGrowthStage;
import org.terasology.simpleFarming.components.SeedDefinitionComponent;
import org.terasology.simpleFarming.events.AddGenomeRetention;
import org.terasology.simpleFarming.events.BeforePlanted;
import org.terasology.simpleFarming.events.ProduceCreated;
import org.terasology.simpleFarming.events.TransferGenomeEvent;
import org.terasology.simpleFarming.systems.PlantAuthoritySystem;
import org.terasology.utilities.random.FastRandom;
import org.terasology.world.WorldProvider;
import org.terasology.world.block.BlockComponent;

import javax.annotation.Nullable;

/**
* System managing genetics of all plants
*/
@RegisterSystem(RegisterMode.AUTHORITY)
public class GenomeAuthoritySystem extends BaseComponentSystem {
@In
private GenomeRegistry genomeRegistry;
@In
private WorldProvider worldProvider;

private static final Logger LOGGER = LoggerFactory.getLogger(GenomeAuthoritySystem.class);

/**
* Called immediately after a bush has been harvested.
* <p>
* Checks the genome component of the bush and assigns it to the seed if it had genes already.
* If the bush did not have a GenomeComponent, it is assigned as this is the first harvest
* A new Genome Definition is created for the family
*
* @param event the Produce created event
* @param creator the creator(bush) of the produce
*/
@ReceiveEvent
public void onProduceCreated(ProduceCreated event, EntityRef creator) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So some elements of this could go into SF. In particular what I think would work better would be to store information about the specific crops possible genomic stuff as a component on its prefab. Then have SF read that and use the information there to mutate the crop as needed

EntityRef producer = event.getCreator();
GenomeComponent genomeComponent = new GenomeComponent();
EntityRef produce = event.getProduce();
if (producer.hasComponent(GenomeComponent.class)) {
genomeComponent.genomeId = producer.getComponent(GenomeComponent.class).genomeId;
genomeComponent.genes = producer.getComponent(GenomeComponent.class).genes;
} else {
FastRandom rand = new FastRandom();
genomeComponent.genomeId = producer.getParentPrefab().getName();
if (genomeRegistry.getGenomeDefinition(genomeComponent.genomeId) == null) {
LOGGER.info("Defining new genome map for " + genomeComponent.genomeId);
addPropertyMap(producer, genomeComponent.genomeId);
}
//TODO : needs to be random based on vocabulary
genomeComponent.genes =
"" + "ABCDEFGHIJK".charAt(rand.nextInt(9)) + "" + "ABCDEFGHIJK".charAt(rand.nextInt(9)) + "" +
"ABCDEFGHIJK".charAt(rand.nextInt(9));
if (producer != null) {
producer.addOrSaveComponent(genomeComponent);
}
}
produce.addOrSaveComponent(genomeComponent);
}

/**
* Called immediately after a bush has been harvested.
* <p>
* Checks the genome component of the seed and transfers it to the plant that was planted
* if the seed does not contain a genome component, the component is assigned on first harvest
*
* @param event the Before Planted event
* @param plant the plant that is being planted
*/
@ReceiveEvent
public void onBeforePlantedEvent(BeforePlanted event, EntityRef plant) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be in SF

EntityRef seed = event.getSeed();
if (seed.hasComponent(GenomeComponent.class)) {
plant.addOrSaveComponent(seed.getComponent(GenomeComponent.class));
}
}

/**
* Transfers the GenomeComponent across different stages of bush growth
* @param event the Transfer Genome Event
* @param bush the bush that is growing
* @param bushComponent bushComponent to check if it is a bush
* @param genomeComponent genomeComponent to check if the bush has a genomeComponent to pass on
*/
@ReceiveEvent
public void onTransferGenomeEvent(TransferGenomeEvent event, EntityRef bush, BushDefinitionComponent bushComponent, GenomeComponent genomeComponent) {
event.getTransferEntity().addOrSaveComponent(genomeComponent);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be in SF


/**
* Adds the GenomeComponent to the RetainComponentsComponent of an entity
* Event handler added to maintain Genome optional dependency
* @param event the AddGenomeRetention event
* @param entity the entity whose RetainComponentsComponent is to be modified
*/
@ReceiveEvent
public void addGenomeRetentionEvent(AddGenomeRetention event, EntityRef entity){
RetainComponentsComponent retainComponentsComponent = new RetainComponentsComponent();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This both seems mildly unnecessary, because if the only thing RetainComponentsComponent is ever used for is GenomeComponent then why does it need to exist. Wouldn't a simple flag work. Or even just the presence of GenomeComponent

Secondly, this can go in SF fine

retainComponentsComponent.components.add(GenomeComponent.class);
entity.addOrSaveComponent(retainComponentsComponent);
}

@Command(shortDescription = "Prints genome of held item if possible.")
public String heldGenomeCheck(@Sender EntityRef client) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per discord discussion, this will go into genome itself

EntityRef character = client.getComponent(ClientComponent.class).character;
if (character.hasComponent(CharacterHeldItemComponent.class)) {
EntityRef selectedItem = character.getComponent(CharacterHeldItemComponent.class).selectedItem;
if (selectedItem.hasComponent(GenomeComponent.class)) {
return selectedItem.getComponent(GenomeComponent.class).genes;
} else {
return "Held item does not have a Genome Component";
}
} else {
return "Command not valid for current conditions.";
}
}

private void addPropertyMap(EntityRef entity, String genomeId) {
SeedBasedGenomeMap genomeMap = new SeedBasedGenomeMap(worldProvider.getSeed().hashCode());
String geneVocabulary = "ABCDEFGHIJK";
GeneMutator geneMutator = new VocabularyGeneMutator(geneVocabulary);
BreedingAlgorithm continuousBreedingAlgorithm = new ContinuousBreedingAlgorithm(0.3f, geneMutator);
genomeMap.addSeedBasedProperty("filling", 0, 1, 2, Integer.class, continuousBreedingAlgorithm,
new Function<String, Integer>() {
@Nullable
@Override
public Integer apply(@Nullable String input) {
return (input.charAt(0) - 'A' + 5);
}
});
GenomeDefinition genomeDefinition = new GenomeDefinition(continuousBreedingAlgorithm, genomeMap);
genomeRegistry.registerType(genomeId, genomeDefinition);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
package org.terasology.edibleFlora.worldGenerator;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.core.world.generator.facets.FloraFacet;
import org.terasology.edibleFlora.events.OnSpawn;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.prefab.Prefab;
import org.terasology.entitySystem.prefab.PrefabManager;
import org.terasology.genome.component.GenomeComponent;
import org.terasology.math.geom.BaseVector3i;
import org.terasology.registry.CoreRegistry;
import org.terasology.registry.In;
Expand Down Expand Up @@ -51,6 +56,8 @@ public class BushRasterizer implements WorldRasterizerPlugin {
private Block air;
private List<Block> bushes = new ArrayList<>();

private static final Logger LOGGER = LoggerFactory.getLogger("BushRasterizer.class");

@Override
public void initialize() {
blockManager = CoreRegistry.get(BlockManager.class);
Expand Down Expand Up @@ -82,7 +89,10 @@ public void generateChunk(CoreChunk chunk, Region chunkRegion) {
facet.getRelativeEntries().keySet().stream().forEach((BaseVector3i pos) -> {
if (random.nextFloat() < 0.02 && chunk.getBlock(pos).equals(air)) {
Block bush = bushes.get(random.nextInt(bushes.size()));
EntityRef bushEntity = bush.getEntity();
bushEntity.send(new OnSpawn(bushEntity));
chunk.setBlock(pos, bush);
//LOGGER.info(bush.getEntity().getComponent(GenomeComponent.class).genes);
}
});
}
Expand Down