andreixd23 / zombiereloaded

Automatically exported from code.google.com/p/zombiereloaded
0 stars 0 forks source link

Common interfaces (infection, teams and other common stuff between game modes) #258

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
Example problem (by Greyscale):

I have a function in zrc.infection and zriot.infection that checks if zombies 
are currently present.  The problem is modules don't know which one to check.

The obvious solution would be to make a zriot module and a zrc module, but that 
would be a shitty solution with duplicated code basically.  So how can we make 
these modules independent of zrc and zriot and also be able to check if zombies 
are currently spawned in the round?

I'm looking for a simple solution if there is one.  One more complicated 
solution would be to expand functionlib which might be worth it in the long 
run.  The goal here would be to use some functionlib stock that would call the 
correct function based on the current game mode.  And if the game mode doesn't 
support a certain function then throw fatal errors that disable the module that 
called it.

A possible solution (Richard):
Make common interfaces. These are modules that game mode cores use to store 
common stuff between game modes, like whether a player is infected or not. 
Other modules that need this information ask the interface module, not the core 
modules.

Core modules will be responsible for updating the interface module with data. 
We might not even need to store data in core modules.

I wonder if we should make a new folder for these interface modules, to 
separate them from regular modules. They also need a certain name prefix/suffix 
to indicate it's a interface module.

Suggestions are welcome.

Original issue reported on code.google.com by richard.helgeby@gmail.com on 29 May 2011 at 5:26

GoogleCodeExporter commented 8 years ago
This is similar to the teamlib and team managers, where the teamlib acts like 
the interface. Core modules just handle events and do stuff, they usually won't 
get any API functions for other modules.

Original comment by richard.helgeby@gmail.com on 29 May 2011 at 5:35

GoogleCodeExporter commented 8 years ago
To solve this elegantly, I think we need to implement some sort of primitive 
OOP-like inheritance and polymorphism mechanism. 

Speaking of modularity in ZR, I think that each module should be different 
plugin that provide its own related natives. I *do* know that UMC 
(http://code.google.com/p/sourcemod-ultimate-mapchooser/) has recently started 
to implement this technique. 

Original comment by alon.gub...@gmail.com on 29 May 2011 at 6:17

GoogleCodeExporter commented 8 years ago
We can sort of do polymorphism with these interface modules, but I have no idea 
how to make inheritance - or objects in SoucePawn possible. That would need an 
extension anyways. Unless you have some ideas?

We just have to keep this simple. Otherwise we'd just write the plugin in C++ 
as a SM extension or MM plugin.

Separating ZR into small plugins will work, but we're going to give this base 
framework a try. Separate plugins can't get event filters unless they hook all 
events through a event manager plugin. In addition the base is more than just 
module management. It has several utilities and helpers too, like logging (with 
filters), a common menu, helper for config parsing and translation wrappers.

The easiest solution to this problem might be to make interface modules.

Original comment by richard.helgeby@gmail.com on 29 May 2011 at 7:42

GoogleCodeExporter commented 8 years ago
In my opinion, the base plugin should export natives to its utilities and 
helpers (logging, menu, event management, etc). This method will not only solve 
the first issue - it is going to make ZR much, much more simple. Using this 
method we will *automatically* create an API for about everything in ZR. 

About inheritance - I do have some ideas how to implement it but they're all 
really complex and requires SM extension.

Original comment by alon.gub...@gmail.com on 29 May 2011 at 9:56

GoogleCodeExporter commented 8 years ago
This is a bit off-topic, but we've actually had this in mind too. A long time 
ago someone called mbalex tried to spend time redesign ZR this way. He was too 
busy with other stuff that time, so nothing really happened. But this time 
we're actually going for Greyscale's base framework. A new release is already 
delayed too much. It seems to be working pretty well so far.

Not to trash your idea, but separating features into separate plugins require 
natives to access "private" data within those features (and allow others to 
read/modify it too) - unless there's some sort of authentication that only 
allow certain plugins to use the native. By compiling it all into a single 
plugin we can choose exactly what to expose.

Also there will be a lot redundancy so the total binary size will be a lot 
bigger than usual. An example is the war3source plugin with ~90 plugins. Their 
code is pretty short, but compiled it's above 1 MB. Space really isn't an 
issue, though.

Doing object oriented programming layouts in SourcePawn is cool as long as it's 
an easy and simple implementation. I like OOP, but it doesn't need it has to be 
used everywhere. SourcePawn is procedural, so we do most stuff that way. Even 
if we made a OOP framework for SourcePawn we'll just end up rewriting something 
similar to C++. :P

We can protect global variables and functions already, by declaring them static 
and writing get/set functions in modules. And instead of creating objects we 
use arrays and enumerations.

With this new interface module idea, along with game cores and other modules I 
think we have what we need now.

Original comment by richard.helgeby@gmail.com on 31 May 2011 at 4:58

GoogleCodeExporter commented 8 years ago
As far as automatically creating the API, this is also happening with the base 
as we create internal events that will later become forwards.

I think the interface module thing will work.  These modules would be specific 
to certain game modes, so we should have a naming convention.  
(zr.zriot.interface.inc) or somethin' like that?  I will put more thought into 
this later.

Original comment by andrewbo...@gmail.com on 31 May 2011 at 7:38

GoogleCodeExporter commented 8 years ago
It's exactly the opposite, where module interfaces are NOT specific to a game 
mode. We need these interfaces to avoid being dependent on core modules. 
Interface module just adds a layer of abstraction.

If a feature is specific to a game mode it will simply use features in the 
cores directly.

Original comment by richard.helgeby@gmail.com on 31 May 2011 at 11:48

GoogleCodeExporter commented 8 years ago
Okay, lets go on your way. How can I help?

Original comment by alon.gub...@gmail.com on 31 May 2011 at 8:24

GoogleCodeExporter commented 8 years ago
One thing I didn't mention about interface modules is functions (like a 
function for infecting a human).

Modules don't know which core module's infection function to use, so we can do 
the same thing with functions. The interface module will have functions that 
dynamically calls functions in the core module. Core modules register each of 
their functions in the interface module.

When a module need to call a core API function it calls the interface's 
function instead. The interface will dynamically call the correct function 
(that the active core module has set).

The interface modules will be an abstraction layer above core modules. It does 
nothing else but storing data and forwarding calls to the correct place. 
Modules don't need to know about core modules at all because everything they 
need is available through interface modules. Only in special cases they might 
directly use a core module, if a feature is for certain game mode(s) only.

Also note that we're not supposed to make just one interface, but many. One for 
each feature that's common between core modules. So far it looks like we only 
need a infection interface, and maybe a team interface (but that's done in the 
teamlib).

The infection interface could have:
* A boolean array to store who's zombie and not, with get/set functions so core 
infection modules can update the state and other modules read it back.
* A boolean variable to store whether zombies are present (again, with similar 
get/set functions).
* HumanToZombie and ZombieToHuman functions that dynamically calls the correct 
function in the active core module. Core modules sets function IDs when loading.

Original comment by richard.helgeby@gmail.com on 5 Jun 2011 at 8:35

GoogleCodeExporter commented 8 years ago
When a game mode is changed or functions that aren't supported in the core, 
should be reset to not forward (INVALID_FUNCTION).

Core modules will be responsible for initializing and resetting interfaces when 
they are enabled and disabled so that old function pointers doesn't remain in 
the interface.

Each function in the interface will need:
* A private (static) handle to store the function to call.
* A set function to set the function handle.
* A function that calls the stored function (modules call this function).
* Optional: Private (static) variables to store common data between cores. They 
are retrieved through public interface functions.

Original comment by richard.helgeby@gmail.com on 7 Jun 2011 at 10:40

GoogleCodeExporter commented 8 years ago
Interface functions will have the same function signature as functions in the 
cores. This also implies that common core functions must have identical 
signatures in each core.

Original comment by richard.helgeby@gmail.com on 7 Jun 2011 at 10:44