subterfuge-revived / remake-core Goto Github PK
View Code? Open in Web Editor NEWCore repository that holds all game logic for both front end rendering and back end validation.
License: Creative Commons Zero v1.0 Universal
Core repository that holds all game logic for both front end rendering and back end validation.
License: Creative Commons Zero v1.0 Universal
If the map configuration is not setup properly, the map generation code can end up in an infinite loop. This task is to make changes to the map generation so that it does not infinitely loop and will instead be able to load players into the game properly.
This is specifically a case when testing out game creation in unity and having other players join a game that was created. Once the game starts, the app freezes because it gets stuck trying to generate outposts in an impossible configuration and can never find a way to place the outposts in the appropriate configuration.
This task may require changes to the protobuf files to change what parameters of map configuration are able to be set.
Combat is currently very clunky and each possible action that can occur within combat has a complex reversal to undo all of the forward logic. The combat system should be further broken down into smaller individual reversible components that handle each part of the combat phase instead of one large reversible component.
It would be neat if we could track various statistics and metrics about the game and potentially even show these metrics as a graph (in the app?? or through grafana?). Look into potential solutions for displaying metrics and statistics about the game and how we can display them. Some metrics would include:
These metrics should be able to be viewed globally for all players or on a player-by-player basis showing the player's progress throughout time.
One solution to this would be to use InfluxDb to gather the metrics, or maybe we can just add a database table to mongo to collect them. We will need to know how to generate the graphs from the data to determine what data sources we could use.
Would prefer a solution that lets us view the stats in unity but if that is not possible and we have to use grafana or something that is fine as well.
Implement an admin endpoint to send a push notification to all players that are within a specific game.
rpc NotifyPlayersInLobby(NotifyPlayersInLobbyRequest) returns NotifyPlayersInLobbyResponse {}
This will depend on the task to add push notifications
While a game is running, each Player
should have a PlayerStatistics
class which keeps track of things that happen throughout the game and when so that graphs or charts can be created. Naturally, the data will be historic but the class should have functions to calculate the totals.
Each statistic should hold a list of key->value pairs that relate the time at which an event happened as well as the statistic for that event. For example, if a player's drillers participated in combat and they lost 13 drillers on tick 75 the statistic should store either (75, -13) (which shows the delta), or it should show (75, playerTotalDrillers). Either of these methods allows the delta and totals to be determined at any given point. Either storage method is fine, though I think storing the delta will probably be easier.
Some statistics to potentially track:
To give players tactical advantages, a system to hire specialists should be created. This system will be tricky to implement because it needs to use the seeded random generator to generate specialist hires FOR ALL PLAYERS. This is because generating the specialist hires for one player in the game will cause all of the players to get the same set of hires. This system should ensure that the same player is being provided the set of specialists every time with a constant seed.
Solution:
Map<Player, List<HireSet>>
where HireSet
is a set of potential hires for one cycle. This is because the client should know the potential hires for other players to allow someone to know what hires another player could use.PlayerCurrencyEvent
. This is to ensure that the seeded random generator is using the random numbers in the same order for each cycle. If the generation of specialists for a player is delayed until they use a hire then seeded random generator may become out of sync as some players may not login until after another cycle has occurred, causing new specialists to be generated for them when they were not yet generated for the other player.To make the game enjoyable outside of the mutliplayer experience, an 'offline' (will still be online) mode will be added to the game. The idea is to allow players to "extract" neptunium they have earned from their multiplayer games in order to use that in some single-player progression system. This progression system might be something similar to clash of clans or clash royale where players upgrade units over time. Then the user can take the units/cards back into the game with (slightly) more power.
The idea is to not make the upgrades OP such that having a particular upgrade lets a player steamroll another one, but still make it so that getting upgrades are desirable.
Note: This will not be P2W. Players will earn upgrade tokens fast enough to have a solid progression and are not going to have to grind to get these upgrades. Players should be able to get all upgrades within a short amount of time playing the game (Maybe ~1 month for a max unit).
This task is not an implementation task. No code should be written as a result of this task. This task should only include a design of what the system should look like. Pictures, diagrams, etc. that show how the system works. This design will influence future tasks
While players are not connected to the internet, the players are able to play puzzles/strategies. In our game we would like players to be able to make their own puzzles as well as create hypothetical scenarios from their current games. In a puzzle, the player should be able to customize the win condition, as well as place down outposts, specialists, and configure driller counts on outposts for all players. The UI might provide 2 modes that allow launching subs, setting T=0 for the puzzle, and placing objects.
Once a player is done we need a way to save the player's configuration. This is the main part of this issue. We need to design a data model that is able to hold the configured values for the player's puzzle. Off the top of my mind this would be:
{
initialState: [], // list of game objects, their owners, specialists, driller counts, positions, etc. to re-create the game.
creator: {}, // user
timeCreated: {},
puzzleGoal: {}, // goal of puzzle. object or enum? Depends on goals
}
Note: using the initialState
to configure puzzles, this essentially means that we will need to be able to export the whole gameState
as a JSON object at some point in time. We should design for this and make our objects serializable.
This is a pretty large task but is mainly focused around serialization.
Newtonsoft.JSON library isn't playing well with android devices. Coordinate with the unity repository and find a JSON library that is supported within Unity for all devices.
Library should appropriately decode and parse JSON messages.
Android devices are unable to run the game without JSON functionality.
When using the Api
object, the constructor accepts a custom URL which allows local development to be able to change the URL the api sends requests to based on how their backend is setup locally. However, the URL is not static, so any time a dev calls new Api()
to make a network call they will need to pass the URL.
Make the URL parameter in the API static
so that it is set & forget. This means you can pass in the URL once, and all future uses of the API will use the configured URL.
Self explanitory. Maybe pair this with #54
GameState.isPlayerAlive(Player player)
Should be an easy implementation.
This task includes creating a specialist class and creating specialists that inherit this class.
Inputs:
None
Output:
class Lieutenant : EventListener {
...
}
Then in the onEvent method it will verify that the triggered event is the type of event it wants to watch for:
onEvent(Event e) {
if (e.eventType == EventType.onCombat) {
// do stuff
}
}
The current priate targeting algorithm is a linear search until the two points on the course collide. This is inefficient and the point can be found immediately with a bit of calculus or quadratic equation. I was able to determine how to do this when creating the code.
If you can update the SUB.getTargetLocation(Vector2, int)
function to be O(1) instead of O(n) that would greatly optimize performance of determining the destination of a pirate.
The current game logic has no idea how to consider if someone has won or if a player is dead (actually I may have added a check for if a player is dead, I don't remember). Some win conditions should be added to the game that will end the game. Once the win conditions are in place, coordinate with the backend to send a 'gameEnd' command when the game is completed so that the server can verify the end of the game.
Currently, subs can launch with only drillers, allow the user to launch specialists from the source along with the drillers. Set a default of 3 specialists as the carrying capacity on a sub. Currently this would be tested by attempting to move the player's Queen
There are going to be a number of global events that can occur in the game and these events might need to be seen by a different audience. Instead of making unique endpoints for all of the possible different things that could happen at a global level, implement a global "Event" server endpoint.
Users would query this endpoint to get a list of events that effect them (that they have not yet seen if possible...). For example, a global event could include:
GameAnnouncement which displays a pop-up in the app about news or updates
PlayerHonored - Tells a player that they were the most honored player in a game and that they got a bonus 25Np from it
PlayerDiscipline - Tells a player they are being rude and are being disciplined (Muted, LoseNp, Lose Ranked Rating, etc.)
AdminMessage - A personal message to a player from administrators
Likely Others in the future
Implement a REST interface to allow admins to publish these types of global events and a GET endpoint to let players query the ones that apply to them. (Database should include an "appliesTo" string and use "*" if it should be shown to everyone)
When internal server errors occur, that means there is a problem with our software that needs to be fixed. We should be able to intercept all internal server errors and track this data inside of the mongo database for administrators and moderators to track.
Todo:
There is a "SubterfugeCoreTest" project included in the repository, but no instructions on how to run the tests contained within the file. Some documentation could be added to README.md to describe how to run the tests.
In order to make notification bubbles appear in the app, we will need to have some way of knowing what messages a player has seen. The server should implement some new data field to track this and the server should track this when the player accesses a GET endpoint from the server.
NOTE: The 'seen' should only update after results are returned from the GET endpoints.
Once a player has seen (called the GET endpoint) a chat message or game event, the player should be added to the seen
list (or the ID/timestamp).
Maybe each game lobby should have a "New content for Player Ids" field that is a list of user IDs. Then when the players login they will be told of new content that they have not seen (ie. messages / events) before they go into the game. Then once the user loads that content their ID is erased from the list.
This is low priority
In order for players to be able to hire specialists, players must be given a type of currency that can be used in order to hire specialists. This task is not about implementing the specialists system or the system to offer potential hires to the player, but this system simply provides a currency system for the player to be able to use once a hire system is implemented.
This feature should have:
It was suggested that there are multiple currencies (like tokens) so the system should be designed in a way that adding additional currencies is easily done, potentially through a Bank
and a Transaction
when purchasing
When a game has been loaded from an online game, the Game
should have a flag to determine if it is a multiplayer game. This lets unity know if the user's game actions should be submitted to the network or not. This is as easy as adding a flag to the game configuration
When a game is created, the app will send along the game "version", this field will be a string like "2.0.1" which tells the app what ruleset to apply when the game is being executed.
This will need a field in the database and should just be a new parameter to the create_room
or room/<id> PUT
endpoint
Once the player is in a game, they need to be able to communicate to one another. This task is to implement the creation of new groups within a game and the ability for users to send chat messages to one another. There are some gRPC endpoints to help with this but they may not be complete.
Chat messages should include a timestamp of when they were sent, they player who sent them, the message, and the group that it was sent in.
Core currently doesn't deal with shields. This issue would involve creating an interface for any shield-bearing entity that enforces methods such as getShields()
, setShields()
, getMaximumShields()
, setMaximumShields()
, getShieldRecahrdRate()
, setShieldRechargeRate()
.
Classes implementing a shield interface should not just store the int shields
as a value for the current number of shields. Instead they should have a lastCombat
variable and a lastShield
variable. This allows interpolating the shield value at a specific tick & allows using the shieldRegenrationRate to easily determine the current shield value. This is easier than needing to manually increase the # of shields every time a ShieldGenerationEvent
occurs which would have to be generated and stored in the time machine for processing.
Potentially have a ShieldManager
which deals with all things shields for an object.
The backend implemented chat functionality. The Api
should be updated to include endpoints for retrieving chat groups, creating chat groups, and retrieving sending messages to a chat group.
This also requires adding Network response class models that allow deserializing the response from the server into native C# objects.
I don’t believe we will need to integrate the chat objects anywhere else in core except for the Network
folder. The Unity app will be end user of these classes and can just call the Api.getPlayerChatGroups(1);
so there’s no need to implement any functions in the Player
class for example.
When a user creates an account, they will login with their username. However, it is likely that some people will use profanity or other vulgar names. The user database should have a DisplayName
field that Administrators can update for every user. The DisplayName will default to the user's username. All GUIs or other responses should use the DisplayName
as the user's name in order to avoid broadcasting potential profanity.
This will allow the user to still login with their original username and password if their DisplayName is changed
In unison with the Unity team.
Outposts will need to have a list of generated names. Note: The name that is generated for an outpost MUST be the same when the game is reloaded. This means that selecting the outpost names must be done through the SeededRandom
classes using the game's seed to ensure that it will always select the same name for the outpost.
Outpost names should:
Names like "Green Forest" are not valid as this is different in many languages. But things like "London" or "New York" are possibilities as they are proper nouns and won't change based on your language. Someone who speaks french and someone who speaks English should both understand that "London" is the same spot.
The generated class should be dynamic and allow names to be easily added to the list.
This task is to convert to using MongoDB as a database engine instead of Redis. Redis is in-memory which would require the server to have a significant amount of RAM. Additionally, Redis does not allow queries or advanced operations other than fetching all of the records avaliable. Using Mongo we can store the data on disk, which reduces the RAM size, as well as have the ability to perform queries on certain fields instead of having to return the whole table.
This solution is done when:
In order to add strategic gameplay, each player should have a diller capacity. If a player is at or above their capacity, they should not be able to produce any additional drillers until they are underneath their capacity. This can be done by adding a drillerCapacity
variable in the Player.cs
as well as a method to count the total number of units the player owns. Making the FactoryProduceDrillerEvent
check if their owner.GetDrillerCapacity()
and the total driller count will be able to cancel the event before it produces any additional drillers.
This PR should enable push notifications to be sent from the server to the player's device.
Currently this is unknown. You will need to research how to do this and implement the necessary steps to send push notifications. Unity has some utilities that allow you to register the user's device to a notification channel and get the id to be able to send them a notification, see here but we will need our server to be able to send to the google and apple push notification servers.
Not enough time to research this tonight. But this might work better than having the server & core logic separate. I feel bad that I'm just finding this now...
DotNet Core Docker
DotNet Core Web API with database
Swagger automatic API documents
Adding Real Time Capabilities
Authenticating with Real Time
Automated Testing on Controllers
Test middleware with fake server
Load and stress test
Localization
Deploying ASP.NET Core
When a new sub is generated it is assigned a unique ID so that game events are able to reference the correct sub ID when the event data gets parsed. However, the generation of this ID is based off the client's random number generator. Hopefully, you can see where this is going...
Because the IDs are generated for every sub, if a user attempts to launch a sub, but decides to cancel their launch, the ID for that sub would have been generated for the user trying to launch the sub but it wouldn't have been generated for anyone else. Thus the client who launched the sub and canceled is now out of sync.
Furthermore, two clients attempting to launch subs that cannot see each other will end up generating the same ID for their subs, causing two subs with the same ID to exist.
The client should not get out of sync when a sub ID is generated, nor should two subs have the possibility of having the same ID get generated.
Maybe instead of using an ID field for the sub, a UUID could be used instead. This would be garunteed to be unique but would unfortunately take up more bandwidth to transfer the information.
However, it is important to note that the client cannot garunteed generate a unique ID unless the client knows about ALL of the player's game events (which provides the possibility for unlimited vision hacks). The only way to completely mitigate the possibility of duplicate IDs is to make the server generate the sub's ID. However, this would mean the server would need to be able to parse the gameEvent JSON. It also means that on every request to the server, the server would need to re-create the game simulation as well as parse ALL game events (even the events in the future), to ensure no generated sub has the ID that it generated. It would be much easier to just let the client assign the UUID.
!!! Important !!!
When loading game events from the server, clients should throw out game events if a sub's ID collides with another sub.
We need to discuss if we thing UUIDs are reliable enough to avoid collisions or if we want the server to manage the IDs of subs within each game.
If the server relies on a client to generate the UUID of the sub, then there should be absolutely no way for a player to get another player's future events. If one client can see another player's future launches, they could schedule an earlier launch with the same UUID which would cause other clients to throw out the original sender's event. I don't think this is an issue as players should never be able to see another player's future events. If this is the case, I am OK with using client generated UUIDs as the chance of colliding UUIDs is near impossible.
Sonar ranges and visibility is currently not implemented. Taking on this task would include providing a base sonar range, determining if objects are visible to specific players/outposts and modifying the sonar range for a sub/outpost if a specialist with sonar modification effect is at that location.
There should ideally be an interface ISonar
which enforces methods such as getSonarRange()
and setSonarRange()
as well as isVisible(ITargetable)
to determine if something is visible. Then this interface can be applied to outposts and subs.
Note: specialists not yet implemented so ignore them for now, just having an interface which allows setting or modifying the sonar range
The current gRPC implementation is limiting and cannot be accessed by web browsers. It also requires any other developers who want to interface with the game to understand gRPC.
Remove this massive overhead and turn the server into a REST API instead.
Use C# .NET API to turn the server into a REST API instead of a gRPC server.
Implement JWT Authentication, Logging, and implement API Controllers for each of the various services.
I am currently working on this.
Allow outposts to be upgraded, providing an increased output. Once the outpost is captured by an enemy, the outpost level should be downgraded by 1 level. This provides a strategic decision for players to sacrifice drillers for an eventual payoff.
An example of this might be:
Factory:
Lv2 - 25 drillers - increase production by 2d/cycle. (Payoff after 12 cycles)
Lv3 - 50 drillers - increase production by 4d/cycle. (Payoff after 12 cycles)
This shouldn’t be too hard to keep track of, we just need outposts to track their current “level” as well as expose an “upgrade” action to sacrifice the drillers and upgrade the outpost.
This is just a suggestion for consideration but I think it would add some strategic elements being able to play a safe early game and perform upgrades on outposts May payoff in the late game by giving an increased production rate.
Once the gRPC server has been converted to REST, we will want to create a client library that helps facilitate client users of the app. The client library should be able to start an HTTP client but accept pure C# objects to abstract networking from the user.
The client should manage login tokens and allow the user to login without having to manage any tokens or worry about setting any headers.
Once a game ends, we shouldn't keep the data around forever. This will just hog space and the only reason to go back to the game is for historical reasons. Once a game has ended, we should delete the associated game data after a few months to save storage space and ensure that queries don't take a long time
See if there is a NuGet package for a profanity filter and apply it to when players submit a new chat message. Racial slurs or other inappropriate languages should not be allowed in the community at all.
The game library should have the ability to serialize the whole game state at a given time. This means that we can fast foward to Tick 100, and pack the current game state as a JSON. Then we can easily just unpack that JSON in order to 'load' the state at that time. This will be extremely useful for things like:
This ties very closely to #38. #38 should be more focused on the functionality required for the puzzle editor for example: win conditions for the puzzle, etc.
JSON all the way.
Unity provides the ability to get the user's device id. Implement this and send this information to the server when the user registers a new account. Accounts that are created on the same device should not be able to play together.
Admins should be able to ban players from the game. There should be various levels of bans. Implement some endpoints to allow admins to ban players from accessing the game.
Once bans are implemented, make sure that if a player is banned, all requests to endpoints other than the login endpoint are blocked with a "BANNED" response. (This can be done in the gRPC interceptor)
Implement the following endpoint:
rpc GetAllPlayers(GetAllPlayersRequest) returns GetAllPlayersResponse {}
rpc BanPlayer(BanPlayerRequest) returns BanPlayerResponse {}
Banning a player should have:
BannedUntil
, which would get set if their role is one of the banned roles.The GetAllPlayers
endpoint should return a list of all players as well as more confidential information for admins, for example, the device identifier and the email registered. Do NOT return the player's passwords (even though they are hashed).
Additionally, it may be useful to have an endpoint for:
rpc GetPlayerChatLogs(GetPlayerChatLogsRequest) returns GetPlayerChatLogsResponse {}
This would allow us to view all of a player's chat messages (grouped by GameID maybe?) so that we can verify if a player has been sending malicious chat messages.
In order to ensure that players only use one account (and don't multibox) we are going to require that all accounts be linked to a phone number. When a user registers, they MUST provide a valid phone number. When they register, we should integrate with TWILIO (or some other SMS service) in order to send out a text message to the user's phone with a verification code. Create a random 6-8 character/digit code and send that to the user.
We will also then need to make a /api/v1/users/verifySocial
endpoint. This endpoint should be able to verify every social platform
Currently driller production events are added to the time machine after every other production event. This also makes it so that each factory doesn't know about their own production events. Maybe instead of having a global timeline that stores the events in the game, each object should store their own event references and the events automatically get added to the time machine. This would be a nice change as it would let you do things like outpost.getNextProductionEvent()
or sub.getNextCombatEvent()
which are currently not possible in this design. These features are actually quite important as it lets players jump to the entity's upcoming event.
This will be a decent amount of work, and requires a lot of changes but make our lives easier. I may take this task on since it will be a bit complicated to do.
The event queueing system falls into an infinite loop if a Goto(GameTick)
action is performed with two or more LaunchEvents
scheduled in the futureEventQueue
at the same tick.
The scheduler takes the first LaunchEvent
, puts it into the pastEventQueue
and generates the associated CombatEvents
. It does the same for the second LaunchEvent
but then removes the first one and it's CombatEvents
after which it is placed in the futureEventQueue
. This should not happen.
It should be possible to launch more than one sub at the same tick.
Launching more than one sub at the same tick crashes the game.
pastEventQueue
if Goto(Gametick)
refers to a point in the futurepastEventQueue
if Goto(Gametick)
refers to a point in the pastRefactor the class names to implement a space theme instead of the submarine theme. Pretty trivial but needs to be done. Will be confusing if we start to use space themes but our code is referencing submarines.
Implement a way to determine if a game has been victorious. There are various game modes and therefore the method should be able to be used no matter what game mode is being played.
This method is going to be used by the server to verify that games are completed, and, once games are completed, the server will provide players with EXP and other in-game resources. However, don't worry about the server implementation for now.
Create a method, potentially on the GameState
, to determine if the game is over. Return a GameEndEvent
(I might not have the name right, but close to that. This is a model in the Models project).
When testing unity, we sometimes don't always want to be doing integration tests. If the backend is down or having problems this can cause hiccups in the development of the application. We should create a 'simulator' module which will act as though the application is connected to the internet and approve all requests, sending example valid responses. This would help to speed up the development of the application as unity would no longer need to rely on the backend's availability.
Potentially modify the Api
class. We should have an interface for netwrok calls: INetworkCaller
that defines all of the network methods. Then we can implement two instances of the INetworkCaller
, one that provides legit responses through NetworkCaller
and one that provides fake responses through OfflineCaller
. Then the Api class can default instantiate the NetworkCaller
version but replace it with OfflineCaller
if the user calls Api.offlineMode(true)
.
Example:
INetworkCaller
public interface INetworkCaller {
public LoginResponse login(String username, String password);
}
NetworkCaller
public class NetworkCaller : INetworkCaller {
public LoginResponse login(String username, String password) {
// Use current code here. Call out to actual server
}
}
OfflineCaller
public class NetworkCaller : INetworkCaller {
public LoginResponse login(String username, String password) {
// Fake data
return new LoginResponse(fakeUser, fakeToken);
}
}
Api
public class Api {
public INetworkCaller networkCaller { get; };
// Maybe put offline mode into the constructor
public static void offlineMode(bool mode) {
if(mode) {
networkCaller = new OfflineCaller();
} else {
networkCaller = new NetworkCaller();
}
}
}
Self explanitory
The Current Specs (and their effects)
Things to address include:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.