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

Office hours #75

Merged
merged 7 commits into from
Apr 11, 2024
Merged
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
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone

## In Progress

- [ ] Max: Sync the anchor points across clients.

## Items to Develop

- [ ] Fix the ability to exit the game and come back in. Dean talked about what we need to do in Teams.
Expand All @@ -24,6 +22,7 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone

## Done

- [x] Max: Sync the anchor points across clients.
- [x] Max: Collision message and its wiring for the client to then render its own effects.
- [x] Max: The new player should join as an invincible entity. Add this functionality and a system to update it after 3 seconds to be removed from the entity.
- [x] Max: On collision, sandworm breaks apart and is available as food for other snakes
Expand Down Expand Up @@ -54,3 +53,9 @@ A game of Snake built using C# in the MonoGame framework, themed around everyone
- Use netcat on Mac or Linux to see whether the server is available.
`nc -vz 192.168.4.20 3000`
- Turn off your firewall. On macOS that is found in System Preferences > Security & Privacy > Firewall

### Client Prediction and Server Reconcilition

- When input occurs the client does that and send it to the server
- The server receives the client input and upates the game state
- Server Reconcilition happens on the client side for the items that have not been acknowledged by the server
23 changes: 21 additions & 2 deletions src/Client/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Client.Components;
Expand Down Expand Up @@ -84,6 +85,7 @@ public bool initialize(ContentManager contentManager, Controls controls, Graphic
m_systemNetwork.registerNewEntityHandler(handleNewEntity);
m_systemNetwork.registerRemoveEntityHandler(handleRemoveEntity);
m_systemNetwork.registerCollisionHandler(handleCollision);
m_systemNetwork.registerNewAnchorPointHandler(handleNewAnchorPoint);
m_controls = controls;

m_systemKeyboardInput = new Systems.KeyboardInput(new List<Tuple<Shared.Components.Input.Type, Keys>>
Expand Down Expand Up @@ -240,11 +242,29 @@ private void handleRemoveEntity(Shared.Messages.RemoveEntity message)
removeEntity(message.id);
}


private void handleNewAnchorPoint(Shared.Messages.NewAnchorPoint message)
{
if (m_entities.ContainsKey(message.wormHeadId) && !m_entities.Values.ToArray()[0].id.Equals(message.wormHeadId))
{
var wormHead = m_entities[message.wormHeadId];
var worm = WormMovement.getWormFromHead(wormHead, m_entities);
foreach (var segment in worm.Skip(1))
{
segment.get<AnchorQueue>().m_anchorPositions.Enqueue( new Position(message.position, message.orientation));
}
}
}

private void handleCollision(Shared.Messages.Collision message)
{
// We need to know if the collision occurred on the screen of the client
if (m_entities.ContainsKey(message.entity1Id) && m_entities.ContainsKey(message.entity2Id))
{
// Check where our current client is and see if the collision is relevant
var player = m_entities.Values.ToArray()[0];
// TODO: Implement the check for the client's screen here. If it is in the screen then we will handle the collision


if (message.collisionType == Collision.CollisionType.HeadToSpice)
{
Expand All @@ -264,8 +284,7 @@ private void handleCollision(Shared.Messages.Collision message)
// Check the position
var position = message.position;

// Check where our current client is and see if the collision is relevant
// TODO: Implement this


// If it is relevant, we either send a boolean flag to the particle system and collision handling or we call those here.

Expand Down
1 change: 1 addition & 0 deletions src/Client/MessageQueueClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ public bool initialize(string address, ushort port)
m_messageCommand[Shared.Messages.Type.UpdateEntity] = () => { return new UpdateEntity(); };
m_messageCommand[Shared.Messages.Type.RemoveEntity] = () => { return new RemoveEntity(); };
m_messageCommand[Shared.Messages.Type.Collision] = () => { return new Collision(); };
m_messageCommand[Shared.Messages.Type.NewAnchorPoint] = () => { return new NewAnchorPoint(); };

try
{
Expand Down
22 changes: 12 additions & 10 deletions src/Client/Systems/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ public class Network : Shared.Systems.System
public delegate void RemoveEntityHandler(RemoveEntity message);
public delegate void NewEntityHandler(NewEntity message);
public delegate void CollisionHandler(Collision message);
public delegate void NewAnchorPointHandler(NewAnchorPoint message);

private Dictionary<Shared.Messages.Type, Handler> m_commandMap = new Dictionary<Shared.Messages.Type, Handler>();
private RemoveEntityHandler m_removeEntityHandler;
private NewEntityHandler m_newEntityHandler;
private CollisionHandler m_collisionHandler;
private NewAnchorPointHandler m_newAnchorPointHandler;
private uint m_lastMessageId = 0;
private HashSet<uint> m_updatedEntities = new HashSet<uint>();

Expand Down Expand Up @@ -61,6 +63,11 @@ public Network(String playerName) :
m_collisionHandler((Collision)message);
});

registerHandler(Shared.Messages.Type.NewAnchorPoint, (TimeSpan elapsedTime, Message message) =>
{
m_newAnchorPointHandler((NewAnchorPoint)message);
});

}

// Have to implement this because it is abstract in the base class
Expand Down Expand Up @@ -160,6 +167,11 @@ public void registerCollisionHandler(CollisionHandler handler)
{
m_collisionHandler = handler;
}

public void registerNewAnchorPointHandler(NewAnchorPointHandler handler)
{
m_newAnchorPointHandler = handler;
}

/// <summary>
/// Handler for the ConnectAck message. This records the clientId
Expand Down Expand Up @@ -222,15 +234,5 @@ private void handleUpdateEntity(TimeSpan elapsedTime, UpdateEntity message)
}

}

private void updateQueues(Entity head)
{
// var worm = WormMovement.getWormFromHead(head, m_entities);
// var headPos = head.get<Position>();
// foreach (var segment in worm.Skip(1))
// {
// segment.get<AnchorQueue>().m_anchorPositions.Enqueue(headPos);
// }
}
}
}
10 changes: 5 additions & 5 deletions src/Server/GameModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class GameModel
private readonly GrowthHandler m_SystemGrowthHandler = new();
private readonly Network m_systemNetwork = new();
private readonly SpiceGen m_systemSpiceGen = new(mapSize - 200, 300);
private const int wallSize = 100;
private const int mapSize = 3000;

/// <summary>
Expand Down Expand Up @@ -145,7 +146,6 @@ private void generateWalls()
{
// We want to create wall entities around the entire map. 5000x5000 is the size of the map
// We'll create a wall every 100 units
var wallSize = 100;
for (int i = 0; i < mapSize / 100; i++)
{
// Top wall
Expand Down Expand Up @@ -178,6 +178,7 @@ private void createNewWorm(int clientId, string name)
// Create the head
Entity segment = WormHead.create(headStartLocation, name);
segment.add(new Invincible());
m_clientToEntityId[clientId] = segment.id; // Associate the client with the head of the worm

// Create X number of body segments
var parent = segment;
Expand All @@ -192,13 +193,11 @@ private void createNewWorm(int clientId, string name)
}
parent.add(new ChildId(segment.id));
addEntity(parent);
m_clientToEntityId[clientId] = parent.id;
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(parent));
segmentStartLocation = new Vector2(segmentStartLocation.X - 50, segmentStartLocation.Y);
parent = segment;
}
addEntity(segment);
m_clientToEntityId[clientId] = segment.id;
MessageQueueServer.instance.sendMessage(clientId, new NewEntity(segment));

// Step 4: Let all other clients know about this new player
Expand Down Expand Up @@ -235,8 +234,9 @@ private Vector2 getLeastDenseStartLocation()
// We want to start the player in the least dense area of the screen
// For now, we'll just start them randomly generated location
Random random = new Random();
var lowerBound = (int)(300);
var upperBound = (int)(mapSize - 300);
var offset = wallSize * 5;
var lowerBound = offset;
var upperBound = mapSize - offset;
return new Vector2(random.Next(lowerBound, upperBound), random.Next(lowerBound, upperBound));
}
}
Expand Down
Loading
Loading