#๐ Game design choices to help avoid future refactoring
147 messages ยท Page 1 of 1 (latest)
@pale pecan
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
Im making the server side so we dont talk about the client part here because that only shows stuff and dosent do any of the actual logic; when a player sends an update, it gets picked up by an async function, like async def a(event):, this async function reality checks the event to see whether the client is lying or not, basic server stuff (the event contains player id and their request), this is where im stuck, i dont know how to handle the event, heres what i have tried so far:
(the players data is loaded into memory, and each player has their own instance of the Player class holding their data which functions access)
Making a decorator, and putting it on top of every function, eg @catch('CRAFT_ITEM') this one for example catches any craft item request and gives it to the function below it, the function does its job and calls another function to tell the player that the craft was successful (noodle like code, all tangled)
client > a(event) > craft_item > return function
Another approach that i tried is making methods under Player class, like Player.craft etc.. this was my best approach so far, async def a(event) passes event to Player instance of the player who requested the thing (after validating the request), then Player does its stuff, and calls another method called self.return to return whether the request was successful or not (did the item get crafted or not) , but the problem with this design is that the game has too too too many stuff related to players, that if i want to put all of them under the player class, it will become a huge uncleanable mess
client > a(event) > Player > craft_item method > self.return > client
.
My latest and best approach: using best of both methods above, making stuff like craft_item their own seprate functions, and putting the @catch handler inside player class, this means a(event) gets the event, passes it to the players instance who requested it, and the player class will call the required function (eg craft_item) to craft the item, then craft_item returns the response, and player class uses self.return to acknowledge the player
client > a(event) > Player > craft_item > Player > client
Now, my question here is that can this be designed better maybe? or if my latest design has any flaws?
why does your text based game (in a terminal i'm assuming) need a server?
because its not in terminal my friend
it has clients that are connected over telegram messager app
ah so like dank memer
i see i see
idk about that one but yea you get the idea, ask any questions you have that may help you get a clearer vision of what it is, so you can help me better
instead of an event-driven layout, why not a command-based one like discord.py?
!pip discord.py for more info
whats the differencce
- because events come from buttons and buttons are easier than writing a whole command
- both commands and events will be a text, like /craft stick 5 or CRAFT_STICK_5
i figure it would be easier to handle different inputs
wdym by that
you could probably use dpy's arg parser on your telegram inputs
i think you mean something like input.split('_') and use different parts?
well if i was doing it, i'd use a /craft stick 5 layout and then use dpy to add a command: ```py
@bot.command()
async def craft(item: str, amount: int):
...
now when you get the text from your telegram message, you can run `bot.process_commands` on it to get it to find and run the right command
That dosent really suit my system + thats not my main problem/concern if you look at the explanations i gave
My main problem is how to process the data not how to structure the data
What i mean: i gave examples like client > a(event) > Player > craft_item > Player > client or client > a(event) > Player > craft_item method > self.return > client etc in my explanation, i want to find a good way to handle where the event goes
Also please ping me when you respond im in another tab analyzing my code
probably the first one
wait wdym "self.return"
in my explanations self.return is a method under Player class
when i mentioned 'self' before return, this means the function is getting ran inside the Player class
return means return data to the users client
update the user client for new changes
u okay with mentions?
and thats what self means, any other questions my friend?
wouldnt that be better named "respond" or "reply"
Yea, i choose return because if pythons return, but that dosent really matter now, what matters is the main problem
i recommend renaming that
i will, its just a name for demonstration
i still firmly believe this is a more robust and flexible solution
isnt that exactly what im doing
no?
do you have any source code so far btw? i want to see an example if you have any
this is what i understood from your dpy example
@bot.command decorator registeres def craft as a function to listen for craft commands?
oh sure let me show you my event reciever
_event_handlers_registry = {}
def catch(pattern=None):
def wrapper(func):
_event_handlers_registry[pattern] = func
return func
return wrapper
async def mainCallbackHandler(
event
):
func = _event_handlers_registry[event.pattern]
await func(event)
just to demonstrate
its an sketch @stoic kernel
i feel like im missing a use of OOP in this part of the game, which is probably the most important part
you should probably type your parameters
i have no idea what anything in this snippet is meant to be
when you run the script
every function that has the @catch decorator on top will get recorded
like @catch('craft_item')
and when mainCallbackHandler receives an update (its name async def a(event) in my explanations)
it will tie the event to its function and call the function
if you want to make it like this, dpy offers a listener service
thats exactly what im implementing here
it makes functions listen for events
@bot.listen('my_event')
async def whatever():
print("i got called!")
bot.dispatch("my_event") # whatever() gets called

thats exactly what im doing here ...
.
again, i still think a command-based approach would be more flexible, but i have no idea what your inputs look like (mostly because you havent really typed anything)
think of the inputs as the same "commands" thing youre saying
its litteraly the same trust me
and the problem isnt even this
the two are different
they arent
comamnd is a text
my events are a text
its the same
and im impleneting the same so called @bot.listen('my_event')
they are
what makes you say that
because commands are different from events
commands are text that gets parsed into a specific designated function, which is then given any remaining parsed args
events are simply just things that get dispatched when something happens
i call them events
you can extend a command easily by just adding another parameter. adding something else to a payload in an event requires you to update every dispatch call of that event. they're just not the same
but they are same as commands
they are same as the commands are text that gets parsed into a specific designated function, which is then given any remaining parsed args trust me
what
i just called them events because they are commands that come from buttons
just trust me and lets continue
alright fine
thank you.
Now lets move onto the main problem shall we..?
Here are my 2 cents:
Both of the ideas you suggested are roughly the same with the only difference being whether you use OOP or not. I think I would prefer the latter since it could reduce the amount of boilerplate required (looking up user ID, getting specific fields, etc.)
Another thing you could consider is the response method, since using a single function for that means you need to pass in all the request details which your processing functions like craft_item shouldn't care about. Instead, I would wrap those in an Event object and pass them into other functions which can use a method like event.respond(...), similar to how discord.Context works.
for your first cent, i didnt understand what youre reffering to with "latter" and "boilerplate" havent heard those words before..
for your second cent, thats exactly what im doing which i kinda didnt mention the specifics, i only pass the required stuff to something like craft function and nothing else.
and thank you in advance for reading that and answering
"latter" = the second option
"boilerplate" = repetitive code
yea but the latter make a god object aka a massive Player class with like 1000 methods
thats why i inevented the third method
what's the difference between a button for each item which sends a CRAFT_ITEM <item> event and a CRAFT_ITEM <item> command?
I don't think it's necessary to draw distinctions between events/commands
to the server, they mean the same thing
so when you open the crafting table
it shows 10 of the things you can craft with items you have
thats how you pass something like CRAFT_STICK etc..
yes, i just named it event, but it behaves same as command
so there's an event for each craftable item type?
no i have 2 catchers, one is exact match and the other one is pattern match
exact match: GOTO_CAVE
pattern match CRAFT__
twait
CRAFT_*_*
now better
right
I would rather separate on spaces and use match/case but let's not get distracted
i use that so i can use hash map from dicts to find events at o(1) speed
thats not really the concern/problem right now
the problem is how you handle the events, think of all of them as exact events, not pattern because that opens whole another world which i have already solved for myself
I think this has the worst of both worlds since your Player class still has 1000 methods but the functions which actually operate on the data aren't part of the class itself.
one is for finding the function (just like #1389387882967339032 message but in player class) and the other one is for sending the update to the player
read what ive wrote under it client > a(event) > Player > craft_item > Player > client
Yep
I think that's also a reasonable approach
What i wanted help for:
Any better design ideas that can override my exisitng ones and be generally better
Or, an approval of my own design that it wont run into problems later on
the only drawback I see is that commands must be loaded after the Player object is created
so I would move all this to a separate EventHandler class (or similar)
why is that?
nevermind, I think it depends on implementation
I dont have any experience at all with things like this, maybe you can think of a better system? or tweaks that can make it better?
you might want to put all of this in a class, but otherwise I don't see any issues with it
I have a fair amount of d.py experience, so I'm probably a bit biased lol
what are you reffering to by "all of this"? the event handler? the functions ?
d.py is simular to the library im working with in telegram for my game so feel free
decorator + events registry + handle function
good idea my friend, thanks, if you have time ill mention another part and you review the design/idea behind it
the game has "servers" no the server that is the server-side, servers like, different lobbies
each lobby is an instance of the Game class
the Game class has every area in that lobby loaded, caves, mountains, village, etc..
and whenever something happens it sends an update to Player class to update the users ui based on the events
and whenever the player for example requests to mine a block, player class tells game class, game class responds with an update
do they have a system similar to cogs in d.py??
might be worth looking into if you want modularity
idk what that is i havetn used d.py but i know its simular to my lib, can you give a few words on explaining it briefly?
just like in discord, when you send a request, eg a message, you get an update in response saying your message has been sent etc..
if you want to group a bunch of commands together, you can create a cog like this: ```py
class MyCog(commands.Cog):
... # init and stuff
@commands.command()
def command1(...): ...
@commands.command()
def command2(...): ...
Then load the cog, which adds those commands to your bot: ```py
bot.add_cog(MyCog())
oh
the magic is that you can put cogs in separate files which helps logically split your code
understood, thanks
no my commands aka events are just functions like
@catch('craft')
def craft
catch sell
def sell
catch forge
def forge
oh right, you were making your own dispatcher
thats intresting, i should try making something simular
yes
I think it's worth a try
any other suggestions? or any questions ?
glhf :)
!close
This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.