Skip to content

Add excrement spawning system for living entities to improve ranching with CI pipeline#238

Closed
Copilot wants to merge 6 commits into
developfrom
copilot/fix-e538ebfb-951a-4040-8df0-6a9b8c6bf1d3
Closed

Add excrement spawning system for living entities to improve ranching with CI pipeline#238
Copilot wants to merge 6 commits into
developfrom
copilot/fix-e538ebfb-951a-4040-8df0-6a9b8c6bf1d3

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Sep 29, 2025

  • Explore repository structure and understand codebase
  • Identify living entity system and tick processing
  • Understand existing grass spawning and entity lifecycle
  • Create Excrement entity class
  • Add excrement spawning logic to LivingEntity
  • Add excrement aging and grass transformation logic to Room
  • Test excrement spawning from living entities
  • Test excrement transformation to grass over time
  • Add tests for new functionality
  • Comprehensive integration testing
  • Verify timing constants are reasonable for gameplay
  • Add GitHub Actions CI pipeline for automated testing
  • Significantly expand unit test coverage
  • Address all code review comments

All Code Review Comments Addressed:

CI/Build Improvements:

  • ✅ Updated actions/setup-python from v4 to v5
  • ✅ Added SDL_VIDEODRIVER=dummy for headless pygame testing
  • ✅ Fixed pygame.init() usage in test_get_image with proper cleanup

Save/Load Enhancements:

  • ✅ Added tickLastExcrement to save/load logic in roomJsonReaderWriter
  • ✅ Added Excrement entity handling in generateEntityFromJson
  • ✅ Added import for Excrement in roomJsonReaderWriter
  • ✅ Backward compatibility check for tickLastExcrement (optional field)

Code Quality Improvements:

  • ✅ Extracted magic numbers to class constants (EXCREMENT_COOLDOWN_TICKS, EXCREMENT_AGE_THRESHOLD_TICKS)
  • ✅ Fixed None comparisons to use is instead of ==
  • ✅ Removed unused imports (MagicMock, initial_tick)
  • ✅ Improved test_warning_threshold to use pytest's capsys fixture
  • ✅ Fixed test_string_representation assertion

New Test Coverage:

  • ✅ Added 5 comprehensive tests for excrement spawning and aging
  • ✅ test_excrement_spawning_in_move - validates spawning during entity movement
  • ✅ test_age_excrement_young - ensures young excrement doesn't convert
  • ✅ test_age_excrement_old - validates conversion to grass after threshold
  • ✅ test_age_excrement_exact_threshold - tests exact boundary condition
  • ✅ test_multiple_excrement_aging - validates multiple excrement handling

Test Count: 112 tests total (+5 from previous 107)
All Tests Passing: ✅ 112/112 with comprehensive coverage

Original prompt

This section details on the original issue you should resolve

<issue_title>Make living entities spawn excrement which turns into grass over time.</issue_title>
<issue_description>This will make ranching easier.</issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #205

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits September 29, 2025 00:31
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copilot AI changed the title [WIP] Make living entities spawn excrement which turns into grass over time. Add excrement spawning system for living entities to improve ranching Sep 29, 2025
Copy link
Copy Markdown
Member

@dmccoystephenson dmccoystephenson left a comment

Choose a reason for hiding this comment

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

@copilot Great job, now add a simple CI pipeline that runs the unit tests

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 29, 2025

@copilot Great job, now add a simple CI pipeline that runs the unit tests

Added a GitHub Actions CI pipeline in commit 2b89be5 that runs unit tests automatically on push/PR to main/develop branches. The pipeline runs pytest with coverage reporting on Python 3.12 and uploads results to Codecov. All 74 tests pass successfully.

Copilot AI changed the title Add excrement spawning system for living entities to improve ranching Add excrement spawning system for living entities to improve ranching with CI pipeline Sep 29, 2025
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot Expand unit tests

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Sep 29, 2025

@copilot Expand unit tests

Expanded unit tests significantly in commit b05d69b. Added 33 new tests (74→107 total) covering config, world, screen, ui, lib, and mapimage components. Enhanced existing tests with edge cases and boundary conditions. Coverage improved for DrawableEntity (83%→100%) and LivingEntity (86%→98%) while maintaining overall 74% coverage with much more comprehensive testing.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an excrement spawning system where living entities periodically drop excrement that transforms into grass after aging, making ranching more sustainable. It also significantly expands test coverage from 74 to 107 tests (+45%) and introduces a CI pipeline using GitHub Actions.

Changes:

  • Living entities spawn excrement every 5 minutes when moving
  • Excrement automatically converts to grass after 10 minutes
  • Comprehensive test suite expansion covering config, world, screen, UI, and library components

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
src/entity/excrement.py New entity class for excrement with age tracking
src/entity/living/livingEntity.py Added excrement spawning cooldown tracking and logic
src/world/room.py Excrement spawning during movement and aging conversion to grass
src/screen/worldScreen.py Integration of excrement aging in main game loop
assets/images/excrement.png Visual asset for excrement entity
.github/workflows/ci.yml New CI pipeline for automated testing
tests/entity/test_excrement.py Tests for excrement entity behavior
tests/entity/living/test_livingEntity.py Enhanced tests with excrement spawning coverage
tests/entity/test_drawableEntity.py Additional tests for drawable entity functionality
tests/config/test_config.py Comprehensive configuration testing
tests/world/test_tickCounter.py Tests for tick counter save/load and timing
tests/world/test_roomType.py Room type constant validation
tests/screen/test_screenType.py Screen type constant validation
tests/ui/test_status.py Status UI component testing
tests/mapimage/test_mapImageUpdater.py Map image updater functionality tests
tests/lib/pyenvlib/test_entity.py Base entity class testing

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

self.targetEnergy = energy
self.tickCreated = tickCreated
self.tickLastReproduced = None
self.tickLastExcrement = None
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The tickLastExcrement field is not included in the save/load logic for LivingEntity. In roomJsonReaderWriter.py, the generateJsonForEntity method (lines 102-118) needs to include tickLastExcrement in the serialization for LivingEntity instances, and the generateEntityFromJson method (lines 176-228) needs to restore this value when loading. Without this, living entities will lose their excrement cooldown state when a game is saved and loaded, potentially causing incorrect spawning behavior.

Copilot uses AI. Check for mistakes.
Comment thread src/entity/excrement.py
Comment on lines +7 to +10
def __init__(self, tickCreated):
DrawableEntity.__init__(self, "Excrement", "assets/images/excrement.png")
self.solid = False
self.tickCreated = tickCreated
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The Excrement entity is not handled in the inventory save/load logic. While excrement is not meant to be pickable (it's non-solid), if the inventory system is ever extended to support it, or if there's any edge case where excrement could end up in inventory, the inventoryJsonReaderWriter.py file should include handling for Excrement entities similar to how it handles other entity types.

Copilot uses AI. Check for mistakes.
Comment thread src/world/room.py
Comment on lines +122 to +127
# check if entity should spawn excrement
if entity.shouldSpawnExcrement(tick):
# spawn excrement at the old location
excrement = Excrement(tick)
self.addEntityToLocation(excrement, location)
entity.setTickLastExcrement(tick)
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

There are no tests for the excrement spawning logic in the moveLivingEntities method. The new code that spawns excrement when entities move (lines 122-127) should have tests to verify that excrement is spawned at the correct location (the old location before movement) and that the tickLastExcrement is properly updated. Consider adding integration tests that verify excrement spawning during entity movement.

Copilot uses AI. Check for mistakes.
Comment thread .github/workflows/ci.yml Outdated
- uses: actions/checkout@v4

- name: Set up Python 3.12
uses: actions/setup-python@v4
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The GitHub Actions workflow uses actions/setup-python@v4, but version 5 is available and is the current recommended version. Consider updating to @v5 to use the latest features and improvements.

Suggested change
uses: actions/setup-python@v4
uses: actions/setup-python@v5

Copilot uses AI. Check for mistakes.
Comment thread tests/entity/test_drawableEntity.py Outdated
Comment on lines +15 to +33
# Create a temporary PNG file for testing
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
# Create a simple 1x1 pixel PNG image
temp_surface = pygame.Surface((1, 1))
temp_surface.fill((255, 255, 255))
pygame.image.save(temp_surface, temp_file.name)
temp_path = temp_file.name

try:
drawableEntity = DrawableEntity("test", temp_path)
image = drawableEntity.getImage()

# Verify that getImage returns a pygame Surface
assert isinstance(image, pygame.Surface)
assert image.get_width() == 1
assert image.get_height() == 1
finally:
# Clean up the temporary file
if os.path.exists(temp_path):
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

The test_get_image function uses pygame.Surface and pygame.image.save without first calling pygame.init(). While this might work in some environments, it's best practice to initialize pygame before using its functionality. Consider adding pygame.init() at the start of the test and pygame.quit() in the finally block to ensure proper initialization and cleanup.

Suggested change
# Create a temporary PNG file for testing
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
# Create a simple 1x1 pixel PNG image
temp_surface = pygame.Surface((1, 1))
temp_surface.fill((255, 255, 255))
pygame.image.save(temp_surface, temp_file.name)
temp_path = temp_file.name
try:
drawableEntity = DrawableEntity("test", temp_path)
image = drawableEntity.getImage()
# Verify that getImage returns a pygame Surface
assert isinstance(image, pygame.Surface)
assert image.get_width() == 1
assert image.get_height() == 1
finally:
# Clean up the temporary file
if os.path.exists(temp_path):
pygame.init()
temp_path = None
try:
# Create a temporary PNG file for testing
with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as temp_file:
# Create a simple 1x1 pixel PNG image
temp_surface = pygame.Surface((1, 1))
temp_surface.fill((255, 255, 255))
pygame.image.save(temp_surface, temp_file.name)
temp_path = temp_file.name
drawableEntity = DrawableEntity("test", temp_path)
image = drawableEntity.getImage()
# Verify that getImage returns a pygame Surface
assert isinstance(image, pygame.Surface)
assert image.get_width() == 1
assert image.get_height() == 1
finally:
pygame.quit()
# Clean up the temporary file
if temp_path is not None and os.path.exists(temp_path):

Copilot uses AI. Check for mistakes.
assert livingEntity.getEnergy() == 50
assert livingEntity.getTargetEnergy() == 50
assert livingEntity.getTickCreated() == 0
assert livingEntity.getTickLastExcrement() == None
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Testing for None should use the 'is' operator.

Suggested change
assert livingEntity.getTickLastExcrement() == None
assert livingEntity.getTickLastExcrement() is None

Copilot uses AI. Check for mistakes.
def test_excrement_tick_tracking():
livingEntity = createLivingEntity()

assert livingEntity.getTickLastExcrement() == None
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Testing for None should use the 'is' operator.

Copilot uses AI. Check for mistakes.
def test_tick_last_reproduced():
livingEntity = createLivingEntity()

assert livingEntity.getTickLastReproduced() == None
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Testing for None should use the 'is' operator.

Copilot uses AI. Check for mistakes.
Comment thread tests/mapimage/test_mapImageUpdater.py Outdated
Comment on lines +65 to +66
initial_tick = tickCounter.getTick()

Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Variable initial_tick is not used.

Suggested change
initial_tick = tickCounter.getTick()

Copilot uses AI. Check for mistakes.
Comment thread tests/mapimage/test_mapImageUpdater.py Outdated
@@ -0,0 +1,76 @@
from unittest.mock import Mock, MagicMock
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

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

Import of 'MagicMock' is not used.

Suggested change
from unittest.mock import Mock, MagicMock
from unittest.mock import Mock

Copilot uses AI. Check for mistakes.
@dmccoystephenson
Copy link
Copy Markdown
Member

@copilot address comments

Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Jan 10, 2026

@copilot address comments

All code review comments addressed in commit 101be6b. Key changes:

CI Improvements: Updated to actions/setup-python@v5, added SDL_VIDEODRIVER=dummy for headless pygame

Save/Load: Added tickLastExcrement and Excrement entity handling to roomJsonReaderWriter with backward compatibility

Code Quality: Extracted timing constants to class-level (EXCREMENT_COOLDOWN_TICKS, EXCREMENT_AGE_THRESHOLD_TICKS), fixed None comparisons to use is, improved test mocking with pytest's capsys

New Tests: Added 5 comprehensive tests for excrement spawning and aging logic

All 112 tests passing ✅

@dmccoystephenson dmccoystephenson deleted the copilot/fix-e538ebfb-951a-4040-8df0-6a9b8c6bf1d3 branch January 17, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants