Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

Community Reputation

1545 Excellent

About IYP

  • Rank

Personal Information

Recent Profile Visitors

8834 profile views
  1. Messaging Design Pattern (MDP) Components of a program need to communicate with each other. In messaging design pattern this communication is done via sending and processing messages. A third party component called messenger stands between different components and does the task of passing proper messages to proper components. MDP increases decoupling, encapsulation, and reusability by removing component communication from component functionality. (I am not discussing distributed systems here) Implementation This pattern is often implemented using a message processing interface. Any component that wants to work with the messenger should implement this interface. This interface declares a process_message method that processes a message and returns a message to be sent to other components. Issues This implementation causes the following performance issues: Messages are usually broadcasted to all components. For a component to detect whether a message should be processed or not, it should check either the type of the message or some other member of the message. Implementing interface requires inheritance and increases the function call overhead. These performance issues make MDP unsuitable for communicating small amounts information, which puts a limitation on the ways we use the messaging system to communicate. C++ Implementation In my implementation of MDP I had the following concepts in mind: People use C++ to achieve zero-overhead abstraction (This is not java). Messaging should be so cheap that it should be used as the preferred means of communication. The components are available at compile time (we will utilize this to achieve to the goals above). Solution Find the message destination by message type on compile time (eliminates broadcasting). Passing messages are function calls, try to inline them (eliminate overhead). Since messages have different types, the components' interfaces are different (i.e. each have different process_message methods), there is no need for inheritance. Messenger Since the components are available at the compile time, the messenger can make a tuple of the components it's going to handle. The messenger implements pass_message method as the means of passing messages to internal components from external components. Passing messages includes calling process_message of all components, this is broadcasting, but there is a solution to eliminate redundant process_message calls, described later. One more method get_module is implemented to allow access to components. Note that each component after processing a message returns a tuple of messages to be replied, this also has to be taken care of. //messenger.inl #pragma once #include <cstddef> #include <tuple> namespace Messenger { namespace Privates { //Passes a single message to a tuple of modules. template <std::size_t N, std::size_t M> struct message_passer; //Passes a tuple of messages to a tuple of modules. template <std::size_t N, std::size_t M> struct tuple_message_passer; //Passes a tuple of messages to a tuple of modules. template <typename MTT, typename TT> void pass_tuple_message(const MTT messages_tuple, TT& modules_tuple); template <std::size_t M> struct message_passer <0, M> { template <typename MT, typename TT> static void pass_message(const MT& message, TT& modules_tuple) {} }; template <std::size_t N, std::size_t M> struct message_passer { //Pass a single message to a tuple of modules, the order of modules in the tuple, defines the order of the messages being passed. //The result of processing each message is a tuple of messages to be passed to the modules, which is done using pass_tuple_message. template <typename MT, typename TT> static void pass_message(const MT& message, TT& modules_tuple) { pass_tuple_message((std::get<M - N>(modules_tuple)).process_message(message), modules_tuple); message_passer<N - 1, M>::pass_message(message, modules_tuple); } }; template <std::size_t M> struct tuple_message_passer <0, M> { template <typename MTT, typename TT> static void pass_message(const MTT& messages_tuple, TT& modules_tuple) {} }; template <std::size_t N, std::size_t M> struct tuple_message_passer { //Pass a tuple of messages to a tuple of modules. First the first message on the tuple is passed to all of the modules then the rest of the messages are passed in the same manner. template <typename MTT, typename TT> static void pass_message(const MTT& messages_tuple, TT& modules_tuple) { message_passer<std::tuple_size<TT>::value, std::tuple_size<TT>::value>::pass_message(std::get<M - N>(messages_tuple), modules_tuple); tuple_message_passer<N - 1, M>::pass_message(messages_tuple, modules_tuple); } }; //The helper function that passes a tuple of messages to a tuple of modules. template <typename MTT, typename TT> void pass_tuple_message(const MTT messages_tuple, TT& modules_tuple) { tuple_message_passer<std::tuple_size<MTT>::value, std::tuple_size<MTT>::value>::pass_message(messages_tuple, modules_tuple); } } //The messenger template <typename... Ts > class messenger { //The tuple of modules using module_tuple_type = std::tuple<Ts...>; mutable module_tuple_type modules; public: messenger() {} //pass a message to internal modules template <typename MT> void pass_message(const MT& message) const { Privates::message_passer<sizeof... (Ts), sizeof... (Ts)>::pass_message(message, modules); } //get a certain module template <std::size_t N> typename std::tuple_element<N, module_tuple_type>::type &get_module() { return std::get<N>(modules); } }; } Components Each components is a class that implements the process_message method, that takes a const reference message and returns a tuple of const reference messages. The message type will vary between different message processors, meaning a components may have several overloads of the process_message method with varying return types, and each overload only handles one type of a message. In this method since all the messages are broadcasted to all the components, all components should process all the messages, but the goal is to eliminate redundant message processing, this is done using the following piece of code: //messenger-module.inl #pragma once #include <cstddef> #include <tuple> //Note: Add to the end of the module class to process known messages only, other wise you need to define a message processor for each message type. #ifndef PROCESS_KNOWN_MESSAGES_ONLY # define PROCESS_KNOWN_MESSAGES_ONLY public: template<typename MT> std::tuple<> process_message(const MT& message) {return std::tuple<>();} #endif Adding PROCESS_KNOWN_MESSAGES_ONLY to the end of each component class, defines a default message processor that does nothing and returns an empty tuple of messages. This means if no explicit message processor for a message type is defined in the components class, the message processing is done in using this default message processor which can be optimized away. Hence redundant messages are not passed to modules after optimization. Sample component The following module processes messages of type std::string, rest of the messages are processed by default message processor. //test-module-b.inl #pragma once #include <string> #include <iostream> #include "messenger-module.inl" namespace Test { class module_b { public: std::tuple<> process_message(const std::string& message) { std::cout << message << std::endl; return std::tuple<>(); } PROCESS_KNOWN_MESSAGES_ONLY }; } One more step So far components can pass messages, only if they have received a message. In other words they just can reply to a message, they can't pass a message without processing a message. It would be useful if such utility was present to each component to pass a message before or even while processing a message. For a component to pass a message, the component needs access to the messenger which means that these classes will be codependent, not only each component and messenger would become codependent but all components as well would become codependent to each other. I have addressed this problem with a trick as follows, but I am not satisfied with it. Any solutions are welcome Current solution is to add a function that has access to the messenger of the components, which passes the messages to components using the messenger. //test-module.inl #pragma once namespace Test { template<typename MT> void pass_message(const MT& message); } This is included in each component's file, sample component: //test-module-a.inl #pragma once #include "messenger-module.inl" #include "test-module.inl" #include <string> namespace Test { class module_a { public: std::tuple<> process_message(const int& message) { pass_message(std::to_string(message)); return std::tuple<>(); } PROCESS_KNOWN_MESSAGES_ONLY }; } The declaration of the pass_message is provided in the header which allows the use in the component. The definition however is yet to come, which will follow after the instantiation of the messenger, which is as follows. //test-messenger.inl #pragma once #include "messenger.inl" #include "test-module-a.inl" #include "test-module-b.inl" namespace Test { Messenger::messenger<Test::module_a, Test::module_b> test_messenger; template <typename MT> void pass_message(const MT &message) { test_messenger.pass_message(message); } } This is not an elegant way of doing it, but does the job. Pros and cons Cons The performance relies on the optimizer to do it's job. Pros Zero overhead. Increase of encapsulation and decupling. Easy to implement. Thanks for reading, looking forward to your opinions and suggestions. I'm also looking forward on writing a graphics engine using this design pattern, hopefully I'll make time and post the progress here. Code and VS project on GitHub: https://github.com/IYP-Programer-Yeah/MDP/
  2. IYP

    Fifth Engine

    now that makes it interesting, I dig it brah
  3. Having considered 4 judges, the final result was supposed to be the average of the top 3 scores. Maybe having 3 judges would change that decision in the first place. I do agree that 100% might not be feasible or not even necessary but a reasonable percentage of game should be reviewed, I myself think this did not happen.
  4. Yes, that is true, I'm too disappointed at judgment to participate again. This was the 3rd year of our participation and the best of the three years. The first 2 years we did not make time to finish the game, we did not have artists to do the art, and we got bad results, but this year we put our best effort, most of our time and finished the game with almost no bugs. First rant Some judges don't really put the effort, even biased on games, yes the game might be unappealing at first experience, or may at all (there are scores dedicated for these problems), but a judge has agreed to put time, put effort and do his best to look at every single point of the game, becoming a judge is a commitment, it not for fun. Even I as a community reviewer finished some of the games I know judges who didn't. Also as a judge, one should put the effort to fully read the blogs, read other judges' reviews, watch the videos and all that there is to be done, yet the judgment this year was lacking it. Second rant There were supposed to be 4 scores one from each judge, and the best 3 would be averaged, which this chance was take from us, coz one of the judges did not submit, or maybe due to technical problems the submission were not saved, but that in itself shows the lack of commitment, to check your own submissions. The judgment is highly biased on people's opinion, this is completely true, just obvious by look at the judgments and of course understandable, so having more judges widens the opinion variety, and normalizes the bias. The lack of submission just took away this chance. Summery Agreeing to becoming a judge is a commitment, I really appreciate the holding of the event, the sponsors, and the judges, but the other side of the competition, the contestants are valuable as well, and their efforts are even more valuable, and not putting effort to fully understand the game, is just a disrespect to the contestants who put effort on the game. Most of this might be due to lack of time for the judges, but as I said, it's a commitment, you should not commit, if you're not sure you can do it. I have always enjoyed participating, but feeling the disregard against the effort, I don't really think it's any good to participate any more.
  5. IYP

    IYP Bot 2.0

    IYP Bot 2.0 The Idea IYP Bot started as a human behavior mimicking bot, and ended up with an unintended idea. The idea of a general bot that could be programed with a few command over the chat. But for this idea to be implemented I needed to refactor all the existing chat bots and make a general purpose bot. A general chat bot first recognizes a string pattern as a command, and generates a response, and/or does a process depending the on the command. For example a chat history logger, recognizes every string as a command and does the process of storing the strings, or maybe some data mining process over that. So we need a way to define a pattern to be recognized and a way to associate a response and/or process with the defined pattern, so on the event of recognizing the pattern the bot does the process and/or responds with proper response. This process is done by categorizing messages, and adding responses to these categories, so in the event of a string fitting in a category (recognizing the pattern) bot responds with a proper random (explained more on Message Categorization and Response Generation->Response Generation) response from that category (responding and/or doing the process). The specifics of defining these categories and responses will be discussed later on section Message Categorization and Response Generation. For the rest of the document I use the term message for patterns defining a category, and response for a response/process associated with each category. Permission System Interaction Permissions Letting every one program a bot is not a good idea, since a lot of mal-intended people exist on the chat, that may harm your system using the program, or abuse the bot to do harmful acts on the server. This brings the need for a permission system. There are four permission levels (the higher the number of the permission the lower its rank): 1- Admin 2- Whitelisted 3- None 4- Blacklisted All of the permission levels applies to roles, member, and channels, the only exception is that channels can't have the admin permission. For any interaction with the bot you will need a permission. Your permission is evaluated as is explained below: 1- If the bot doesn't know any admins, the first person that sends something that the bot can receive will be assigned the first admin, so you're better off first setting the bot up and then adding it to servers. 2- Admins can assign members, roles, and channels permissions as explained above using command: .Permission [Channel/Member/Role] [White/Black/Admin] [Tag] 3- Admins override permission of their roles and the channels they are interacting with the bot in. 4- If a member has a permission other than None assigned to him/her the permission of his roles will not influence his/her permission. 5- If a member is assigned None permission, highest ranked permission of the roles of the member, is used as the member's permission. 6- If member's permission (evaluated from rules 4 and 5) is not Admin the final permission to interact with the bot will be evaluated from the minimum of the member permission and channel permission. 7- If the final evaluated permission from rule 6 is Blacklisted the bot will ignore all of the messages from the member. If the permission is None, member can use commands that are already added to the bot by members. If the permission is Whitelisted the member can use the bot's built in commands to program the bot. Notice: Interaction through bot's DM is possible, this means that permissions assigned to roles and channels will not apply to DM interactions. Test/Final Feature Every new message or response that a member submits to the bot is considered a test feature, meaning it can only be used on channels that are designated test channels, or they should be set as final feature by an Admin permissioned member. Admins can add channels to designated test channel or remove them from designated test channels using the commands: .AddChannelToTest .RemoveChannelFromTest These commands add/remove the channel they are sent in to/from designated test channel list. Admins can set messages and responses to test/final features using the commands: .SetMessageAsTest [Category][Message ID] .SetMessageAsFinal[Category][Message ID] .SetResponseAsTest [Category][Response ID] .SetResponseAsFinal[Category][Response ID] I will explain more on how to acquire Message ID and Response ID on section Bot Elements->Category. Bot Elements Programs A program is a java source code with exactly one public class, the public static functions of the class will be accessible on messages and responses. You can add/remove/list programs using following commands: .NewProgram [Public Class Name][Program] .RemoveProgram [Public Class Name] .ListPrograms The methods you will be calling will have 2 arguments first one of type String[], and the second one of type Message from package: de.btobastian.javacord.entities.message.Message; So you should import this packet on your programs which will allow Discord API integration. The javacord message object passes as second argument will be the message object generated by javacord on even of the receiving the message that triggered the bot. The return value of a method called on messages should be of type Boolean, and of type String on responses. Resources Each resource is a set of strings represented by a name, each string is called an element of the resource. You can manipulate resources using following commands: .NewRes [Resource Name] .AddToRes [Resource Name][Element1][Element2][Element3]...[Elementn] .RemoveRes [Resource Name] .RemoveFromRes [Resource Name][Element] .ListRess .ListResElements [Resource Name] There is a default resource named * and contains every string by default. Category A category contains a set of messages (patterns) and a set of responses represented by a name. You can manipulate categories by following commands: .NewCat [Category Name] .AddMessage [Category Name][Message] .AddResponse [Category Name][Response] .EditMessage[Category Name][Message ID][Message] .EditResponse[Category Name][Response ID][Response] .RemoveCat [Category Name] .RemoveMessage [Category Name][Message] .RemoveResponse [Category Name][Response] .ListCats .ListMessages [Category Name] .ListResponces [Category Name] Following commands list the messages/responses with their ID: .ListMessages [Category Name] .ListResponces [Category Name] Message Categorization and Response Generation A string fits in a category if it matches any of the messages in a category. Messages and responses have the same structure. Message/Response Structure Each message/response is an ordered list of message parts, a message part can be one of the following: Raw Message Part: A raw message part is a raw string. Mention Tag Message Part : A mention tag message part can be the mention tag of the bot, or the mention tag of the sender of the string, each represented by @bot (bot's mention tag) and @sender (sender's mention tag). Sytnax: @sender @bot Resource Message Part: A resource message part is an instance of a resource, with properties of ID, repetition counts, case sensitivity and the name of the corresponding resource the message part is an instance of. Syntax: <Resource Name>{ID}{Count}{Case Sensitivity} ID, Count, and Case Sensitivity are optional, you can leave them empty or not even use them, any of the following are correct resources message parts: <Resource Name> <Resource Name>{ID/Empty} <Resource Name>{ID/Empty}{Count/Empty} <Resource Name>{ID/Empty}{Count/Empty}{Case Sensitivity/Empty} ID allows the resource to be referenced and its value to be used in response generation or as input for programs and its value can be any integer, the default value is -1, any resource with an ID of -1 will be treated as if no ID is assigned to it. Count defines the repetition count and can be any non-negative integer, * or +. * represents any repetition count including 0, + represents any positive repetition count. The default value is 1. Case sensitivity defines the case sensitivity of the message part, it can be true (case sensitive) or false (case insensitive). Program Message Part: A program message part is a function call of a java static function that returns either a Boolean (on messages) or a String (on responses). Syntax: ~ClassName.FunctionName(<ResourceName1>{ID/Empty}, <ResourceName2>{ID/Empty}...,<ResourceNamen>{ID/Empty})~ Any correct resource message part form is acceptable for function arguments. Notice: The * resource can not be used in the argument list w/o being a reference. A typical form of a message/response: <greetings> @sender this is my first response, i <empty/dont>{0} want ~Program.function(<empty/dont>{0})~ program to run. Matching a Message A message matches a string \(S = A_{1}A_{2}A_{3}...A_{n}\) where each \(A_i\) is a sub-string of \(S\) that can have the length \(0\), if and only if for every \(i\) the \(i\)-th message part accepts \(A_i\). Each message part accepts a string as follows: Raw Message Message Part: A raw message part accepts a string that is equal to its raw string, the case sensitivity, is defined by the case sensitivity of the message. Mention Tag Message Part: A mention tag message part accepts the sender's mention tag in the case of @sender and bot's mention tag in the case of @bot. Resource Message Part: A resource message part accepts a string if it's a repetition of the elements of the corresponding resource by the repetition count of the message part, the case sensitivity is defined by the message part's case sensitivity. Program Message Part: A program message part accepts a string if the return value of its function call, is true. The arguments of the function call are resources, if these resources have IDs that are not equal to -1, they are references to resources that are used in the message that match the ID and resource name. To generate the first argument of the function which is an array of strings, if the resource is a reference the accepted sub-string by that resource is associated with the resource, and if the resource is not a reference a random string accepted by the resource is associated with the resource. Each element of the first argument array will be the string associated with each argument resource in order of their appearance, except the last element of the array which will be the sub-string associated with the program. The argument resources that have an integer value for Count that is greater than 1 will be considered several resources with the same ID and name, and will have separate string in the first argument. Notice: There are two kind of messages, interrupting and non-interrupting, if the string is matched with an interrupting message, if will not be matched by any other messages, but if it's matched by a non-interrupting message, it has a chance to be matched by other messages. For each matched message a proper response will be generated. You can use following command to change a message to interrupting and non-interrupting, by default all messages are interrupting. .SetMessageInterrupting [Category Name][Message ID][True/False] Response Generation A response has the same structure of a message, the only difference is that on response generation each message part is substituted by a string as follows: Raw Message Message Part: A raw message part is substituted for the raw string. Mention Tag Message Part: A mention tag message part is substituted for the mention tag of the bot or sender, depending on the it's value being either @bot, or @sender. Resource Message Part: A resource message with and ID that is not -1 will be reference to the resource message part on the message with same name and id, if no such resource is found it will be treated as if it's not a reference. If the resource message part is a reference it will be substituted for the string the referenced resource message part accepted. This can be used to use sub-strings from the message in the generated response. If the resource message part is not a reference it's substituted for a random string that the resource message part accepts. Program Message Part: The program message part is substituted with it's return value. The resource message part arguments, if reference resource message parts, will be associated with the sub-string referenced resource message part has accepted other wise the resource will be associated with a random string that the resource message part accepts. The first argument is an array of strings and each element of the array will be equal to the string associated with each resource message part, in the order of appearance. Notice: On the even of any program returning null, the response generation will be terminated, this can be useful for logging program that don't intend to generate responses. Notice: Some of the messages and responses can generate warnings, to receive or stop receiving warnings use follow commands: .NotifyMeWarnings .Don'tNotifyMeWarnings Notice: On response generation a response is chose that the referenced resource message parts of it, bets fits the available resource message part on the message. If several of the same level of compatibility is found, a random one is chosen. Save/Load/Merge/Reset Database Every thing added to the bot, is considered part of it's current database, you can manipulated the database by following commands: .SaveDatabase [File Name] .LoadDatabase [File Name] .MergerDatabase [File Name] .Reset Thanks for reading the fairly technical doc, if interested in actually using the bot join my test channel on discord: https://discord.gg/nuzz6z6 Also source code available on: https://github.com/IYP-Programer-Yeah/IYP_Bot-2.0 Also I tried to get this out as soon as possible so there are probably a lot of typos, i'll appreciate any suggestions on better phrasing, error fixings and syntax simplification.
  6. IYP

    WoA V - Afterparty/Judging thread

    @ArThor thanks for reviewing our game, did you play on easy mode, coz you mentioned it was too difficult, also the training level does not have background music, but there are sounds for rotating dominoes (right click) making the dominoes fall (left click), dominoes touching each other, and in general dominoes moving. Thanks again for playing the game.
  7. IYP

    WoA V - Afterparty/Judging thread

    @Endurion I saw that you had performance problems on the game, I may soon upload a more optimized version for those who want to try the game, also If I may ask, what were the specifications on your system? also thanks for the feed back, really appreciate it.
  8. IYP

    WoA V - Afterparty/Judging thread

    did anyone have performance problems with our game? Sorry, I just noticed the post, were you able to run the game, or you still have the problem?
  9. IYP

    WoA V - Afterparty/Judging thread

    On easy mode, always aim for the top center of the domino unless it's too close. Also for the change in difficulty you should restart the game for the changes to take action, on normal you should just position yourself properly on the current domino to get to next, meaning if you are too far from the other domino, walk a little on the current domino, then jump, if you are too close, jump early till you are in mid, on turns try to choose a line between the two dominoes that is almost the length of the default straight line dominoes, this way you'll probably land well, the thing is that the jump helper, helps on little difference of length on jump, but if the difference is too much it's not gonna help, so you cant jump too far, or too close. For the turn and push, you should land on center, turn the domino, then walk till in proper position to jump, then push and jump,. though all of this should happen under like a 0.1 of second . I myself play like this though I believe if you play some more, you'll find some decent methods of yourself XD. thanks for playing
  10. IYP

    WoA V - Afterparty/Judging thread

    am I late to the party?
  11. IYP

    WoA V - The Competition Thread

    There we go, the competition is over and we have a game
  12. IYP

    WoA V Day 7

    So today our artists finished the art, we applied it, finished the menu, save and polished out stuff, then did a little optimization and the rest (the last 3 hours that only I was awake of the whole team) I spent on debugging. This year we had 2 artist and I really thank them for the amazing art they did, loved it XD. So no videos for today, if you wanna play it though here is the link: https://drive.google.com/open?id=0ByRMOIz9rEO0MkU2cUtWSXlfd3M One thing I'm interested in is to see how people solve the puzzles and how fast they can finish the levels, and what their max score are, so any one who plays the game, I'd appreciate if they could take the time to share some feed backs or a video (which will be awesome). Tomorrow I'll post a review on our work on WoA, and few days later, I will send my solutions for the levels XD. Good luck to every one Also we have 3 minor bugs I dare the judges to find
  13. IYP

    WoA V Day 6

    Special thanks to our artists XD, every level a custom theme, which is why we only have 2, but 2 is more than enough since it takes long to finish
  14. IYP

    WoA V - The Competition Thread

    6th day over, here's the blog
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!