Posts by Miwarre

    java already allows for a consumer/producer relationship between threads. And it would make a lot of sense to set this up if you are making threads out of each plugin component for asynchronous tasks.

    @zfoxfire: well, this is quite a different thing; communication between threads is one thing; inter-communication between different objects neither of which is responsible for launching the other (and then it cannot held a convenient pointer to the other, as your example shows) is different. Of course there are technologies for this, which I listed in my OP.


    Ultimately however, one of sides will need to access at run time the definition of the other class and this was not possible before the last update (I have not tested this point yet, but I assume now it is possible).


    At this point, one plug-in can directly and synchronously access the public methods of another plug-in via the API Plugin.getPluginByID/Name() methods and cumbersome asynchronous methods like the ones described by @nobotious and zfoxfire are no longer needed.

    Possible consequences of the above, illustrated by the following scenario:


    *) We have a component, say a menu, which is created when needed and registered as listener (listening for mouse clicks or for key strokes), un-registering the main plug-in listener.
    *) The component does its job and then each of its elements are carefully removed from the player GUI, all children removed from their parents (which, incidentally, sounds quite horrible... ), instance(s) of the component de-referenced and so on.
    *) The main plug-in listener is re-registered.


    1) We end up with 3 listeners being active: the original registration of the main listener, the component listener, the second registration of the main listener, while one at most was intended to be active at a time. Repeat the process a few times and we will have a plethora of listeners all active...


    2) The component, being still referenced by the Event Manager (i.e. by whichever part of the API is responsible for dispatching the events to the listeners), is never garbage collected. In fact n instances of it may occupy memory (and handle events pestering each other) if the process is repeated n times.

    Is it possible that Plugin.unregisterEventListener() does nothing? I tried with the following simple test plug-in which:


    1) in its onEnable(), register itself, unregister itself and than register itself again;


    2) in its PlayerCommandEvent handler, simply echo any command to the chat.


    Expected Result: the command is echoed only once.


    Actual Result: the command is echoed twice, as if the unregisterEventListener() call in onEnable() did nothing and there were TWO listeners.


    Very cool but i think the rising world team are also building a new protection script oO well thats what red51 told me some months ago, i guess if they do make one it would not harm anyone to have two :D

    I assumed that too. But, seeing that it was not included (or posted in some way) in the API release and all the pieces were already there, I though to go on...

    If you look through the rest of the forum you know (or I hope) we are never spitefully.

    Sure; this community is very nice indeed. So, for added clarity: no offence taken, as clearly no offence was intended; just a gentle reminder that sometime wording is important...

    Realism is RW hmm sometimes yes sometimes no.... When you smelt ore it is one to one. When you make a crafting table you split a couple logs and poof a table!! (wish I knew that when I built my engine table...)

    As I already said in other posts, in my perspective, "realism" is a short-cut for a more articulated concept, which does not necessarily means a verbatim replica of our world. The reality as we know it is the easiest metre for "realism", but it might well be a different world, as long as it is self-consistent and coherent it can still be "realistic" ("verisimilar" might be a more appropriate word, if I understand it correctly).


    What I would find unappealing is a context in which things happen for no reason (except for them being fashionable), with no cause and no purpose.


    Then of course, this being a game, it is expected that things might be simplified, corners cut and processes streamlined; my point is not about a slavish attention to trivial details, but a general meaningfulness of the world the player is immersed into.

    Natural disasters would be really nice!

    I hope to understand the spirit of those comments. But, as in our country in a couple of weeks we just has two earthquakes in a row where several persons died, perhaps someone would have appreciated a less hilarious approach...


    Anyway, yes, this could add realism to the game play. Earthquakes do not happen randomly, though. Do Rising World simulate tectonic plates or seismic faults (or however they are called in English), at least in some simple way or will it do in the future?


    Random earthquakes without a reason would simply be a lottery (which I personally find quite boring). Earthquakes with a reason and a context would be a challenge and a stimulus.

    True. But it would be nice, it's very real. And then it commits us to build safer buildings :D

    Taking construction quality into account would be a GREAT addition!


    However, anti-seismic construction is a quite complex matter. As long as RW does not even simulate gravity, not to speak of weights and resilience of the materials (again even in some simple way), I fail to see how it could even start to scratch the surface of these topics...

    A first announce to disclose that I am working on a Java plug-in for Area Protection and Management.


    It is not a port, it is a complete rewrite from scratch. I am trying to go as much visual and GUI-ish as possible, so the progress is not very quick. A couple of screen shots to show some of the work so far.


    There will be only ONE chat command, which will bring up this main plug-in menu (with clickable items):



    The New Area command opens the area selection tool to create the new area; details about the area being created (centre location and sizes along the two coordinates) are displayed in real time in the info panel:



    The idea is to be backward compatible with the existing areas, if possible, but this plug-in will allow to set the permissions of each area individually.


    Stay tuned!

    That's unfortunately a limitation of the collision shapes :/ Probably it would be favorable to move the player as well as long as the elevator moves (by using the moveTo() method)

    Well, thinking again, the very moveTo() method does not seem to work even with a WorldElement (i.e. the elevator itself), as described in this thread. I did the test described in the OP using setPostion() instead (which also has problems, but they can be 'worked around').

    Yeah, this would work of course (after making the addUrl() method accessible via reflection

    Indeed (I summarised a bit the process, but of course you got the details...).

    it's favorable to have (a) separate classloader(s) for the plugins when it comes to reloading[...]

    Yes, I understand (well, let's say I do... ;) ). I am confident you'll find the most "acceptable" way to address this point.

    that's why I'm Cramming everything into one plugin, no sense of making 20 plugins when all you have to do is keep adding featues to the one you currently have, I was going to make a separate mail plugin but that will put into EffNet, along with money and shopping.,

    Everyone is entitled of his own preferences, of course. My preference is for distributed development: quicker and of better quality, usually.

    Hmm... this is indeed a problem (it makes the getPluginByID/Name() methods rather useless). Currently each plugin has an own classloader (in order to be able to unload a plugin properly), unfortunately these classloaders don't know anything about each other. Basically even a minor change (load all plugin by a single classloader) would do the trick, but first we have to make sure this doesn't result in any other issues (especially regarding the ability to reload plugins on the fly).

    I expected there were reasons for such a set up and they make sense.


    If it is of any help, this is what I tried: from one plug-in, I accessed the System Class Loaded (ClassLoader.getSystemClassLoader()) to use its addUrl() method to add the plug-in .jar path. This is enough for any other plug-in to access the class def of that specific plug-in. So perhaps it is not necessary to modify the class loader of each plug-in, the system class loader is enough (not that I do understand everything of this, particularly knowing nothing of the internal set-up, but I do my best to pretend I do... :S ).

    DISCLAIMER: This post will be long and boring and it will raise non-trivial Java topics (which I am not sure to understand 100% myself, being a C++ programmer, before than a Java programmer...). However, at least the first section Why? might be of general interest.


    Why?


    The two following example scenarios should show why Inter Plug-In Communication (IPIC) might be useful:


    Scenario A:


    1) Assuming we already have an "Area Protection" plug-in with some basic features and a "Money" plug-in also with some basic features;


    2) A new "Shop" plug-in is developed, implementing shops, for instance using chests or crates as item containers.


    3) This "Shop" plug-in would find useful to query the "Area Protection" plug-in for chest accessibility (we do not want buyers to access any chest, only those in unprotected areas or in specially defined shop areas) and to query the "Money" plug-in to check if the buyer has enough money or to tell it to subtract the relevant amount in case of a buy.


    This is to avoid to have (almost) anything in (almost) any plug-in. Once the first two plug-ins provide some basic features, other plug-in can add more features, piggybacking on them. Note that even including the "Shop" feature in the "Money" plug-in would not avoid the need to query the "Area Protection" plug-in for chest accessibility (or vice-versa if the shop feature is implemented in the "Area Protection" plug-in).


    Scenario B:


    1) Assuming there is an "Objects" plug-in which places static objects (and we have one!!!); it may have interesting features like visibility management depending on player distance, or some simple animations (let's say rotating elements);


    2) A new plug-in is developed which implements wind mill (to produce flour or olive oil or whatever) or water-driven power facilities (and electricity management).


    3) The latter plug-in might find useful to ask the "Objects" plug-in to display its mills or power facilities rather than re-inventing the wheel from scratch; it may also take advantage of any improvement the other plug-in may gain over time.


    In practice, IPIC would allow each plug-in to leverage whatever feature other plug-ins already have and decided to share, minimising development effort and maximising features and feature quality, as each plug-in could focus on its 'core business', making it as polished and as robust as possible, without being distracted by nice-to-have but collateral features, which could become the 'core business' of other plug-ins.


    How?


    This is where things go muddy...


    Before looking elsewhere or waiting for some API expansion, I looked at what the current plug-in API has to offer right now. And I found at least two areas:


    *) Custom events (supported by the Plugin.triggerEvent() method). This might be useful for some kind of IPIC, but it seems to be intended for notifying of some context change whomever might be interested, more than to query a specific plug-in for a specific datum or action. It is also cumbersome to get one or more return values (query) from this methodology. There are work-around, involving synchronisation and custom objects defined by each plug-in to pass data back and forth, but they are cumbersome and not very robust.


    *) Direct plug-in access (supported by the Plugin.getPluginByID/Name() methods). This allows to retrieve an instance of a specific plug-in and, potentially, to invoke any of its public methods: quite near to the mark!


    Unfortunately, both methodologies suffer from a serious drawback: both require the target plug-in to be in the CLASSPATH. Apparently, no plug-in .jar is in the CLASSPATH (which makes sense from some point of view), so no plug-in can access the definition of other plug-in classes (or inner classes); trying results in a run-time java.lang.ClassNotFoundException.


    There are ways to dynamically add plug-in .jar's to the CLASSPATH, which involve ugly tricks based on reflection. I tried on a local dedicated server and it works: I could call a public method of a plug-in from another plug-in.


    In principle, it would be possible to encapsulate these tricks in a specific IPIC plug-in, exposing neater methods for other plug-ins to register themselves as sources and publish methods, making the life of plug-in developers easier. Still, there seems to be no way to ensure this plug-in would be loaded first to be immediately available to other plug-ins (registration of a source plug-in is likely to happen at plug-in onEnable() )


    Then, there are the already invented wheels:


    *) JMX and its various flavours of MBean's: it has the advantage to be already included in any JVM and to be relatively easy to use, once you know its concepts. I have not tried it yet in the RW context, but I assume it is going to work. Still, forcing plug-in developers to learn another (slightly esoteric) technology in order to create plug-ins is not going to help a wide adoption of the IPIC concept (rather useful, as we saw).


    Again, it is possible to hide the technicalities in an IPIC specific plug-in, providing other plug-ins with 'simple' ways to publish access to data and methods (if they choose to), but still it would be necessary to ensure that this plug-in would be loaded before any other, and this do not seem possible at the moment.


    *) OSGI is the obvious 'big guy' of the block. However, it might be over-kill and it is likely to require a built-in support form the RW framework itself. So, not for now, I'm afraid.


    *) Java Module System also looks appropriate, but it was not here yet, last time I checked.


    In summary, there are ways to implement IPIC right now. However, all of them have a more or less steep learning curve, require more or less esoteric code snippets to be added to the plug-in source and none is really 'plug and play'. Worth pursuing anyway?


    If anyone has other suggestions, proposals, comments, I am eager to hear them!

    A) There might be more than one reason for an error in line 80; knowing the exact error reported would help. One of the most common reasons and the first coming to my mind is that the result of p.getAttribute("money") cannot be cast to an int.


    This may happen for instance if the attribute "money" is not set for that player.


    If I understand correctly the code, that attribute is initially set in line 60, upon retrieving the player money amount from the DB; however, it is only set if an amount is retrieved; if in the DB there is no row for that player, if(result.next()) in line 55 fails and the attribute is not set, causing an error in line 80.


    Can a row for a certain player be lacking in the DB? Sure, as the INSERT query in line 39 is never executed. So, it seems to me that no row is ever created in the DB. It seems to me that a db.executeUpdate(query); statement is missing in line 40 (but see C) below).


    This, presumably..., for the line 80 error. There are a few other issues in your code.


    B) An SQLite connection is open in line 20 of onEnable(), but another one is open and used in line 50 of the PlayerCommandEvent event. Having multiple connections to the same DB is possible, but is usually unnecessary (and a source of troubles).


    As Database db is a field of the class and is available to all its (non-static) methods, I do not see any reason to open a second connection with the same data base (and, in addition, to do this each time a player types a command in the chat, even a command totally unrelated with your plug-in).


    So, unless I am missing something, I would remove the content of line 50.


    C) It seems to me that the query in line 39 would not do what I presume you want to do. In line 39, I presume you want to add a new record with an initial default amount of money, but only if the player is a new player who never logged on the server before; I don't think you want to add another row for a player each time that player logs on. But this is what the query in line 39 would do.


    It is possible to check if a row for that player already exists and add a new one if none is found in several explicit steps, but the more compact and quickest way is to use SQL itself:


    1. Adding a PRIMARY KEY clause to the player_name column will force that column to have unique values, i.e. there can be only one row for each player, attempting to insert a second row for the same player would cause an error:
    'player_name' CHAR(64) NOT NULL DEFAULT ('[NoName]') PRIMARY KEY,
    (this would also create an index on 'player_name' speeding up queries based on it, which presumably is your main search criterion).


    2. Adding an OR IGNORE clause to the query in line 39:
    "INSERT OR IGNORE INTO Money ('player_name', 'Player_money') VALUES ('"+playerName+"', 2000);"
    will add a new row if there is no row for that player, while ignoring the resulting error and skipping the INSERT itself if a row already exists for him.


    At that point, a row (and only one) surely exists for that player in the DB. Here, in the PlayerSpawnEvent event, it is the right place for the query in lines 51 - 66, being sure to always set the "money" attribute, even if the query fails (because of an error or for whatever reason). For instance by unconditionally set it to a default value (0?) before the query or in the catch block.


    (Incidentally, in this way the SQL query (which is potentially expensive resource-wise) is executed at most once for each player login.)


    D) A small optimisation detail for the query in line 104: you are already sure that the "player_name" for the row to update is already the needed one (the WHERE clause ensures this), then the first value set is useless and it is enough to do:
    "UPDATE Money SET Player_money=666 WHERE player_name = '"+playerName+"'"


    The moral of the story: a reasonable familiarity with SQL is important: RTFM!! ;)

    Still working on elevators, which seem to stress the API a bit... :/


    Two possibilities:


    A) If the model of the elevator is created with a Hull collision shape:


    model.setCollisionShape(CollisionShape.createHullCollisionShape());


    *) A player standing on the model is correctly brought up and down when the model moves up and down (well, a bit shakily, but it works).
    *) But of course he cannot enter inside of the elevator cabin, which has been defined as a solid hull by the collision shape.


    B) If the model of the elevator is created with a Mesh collision shape:


    model.setCollisionShape(CollisionShape.createMeshCollisionShape());


    *) A player can enter the elevator cabin (no longer a solid hull but a hollow mesh).
    *) But, when standing in it, if the elevator moves up, the player remains at its current position and eventually falls to the ground below the elevator (note that when the elevator moves down, the player meets a solid elevator floor when 'catching up' with the descent; so, again a bit shakily, but down movement works).


    Am I overlooking something? There are other ways to achieve this required result (hollow cabins, which are however solid) ?

    Scenario:


    1) A plug-in turns on listening on some key strokes:


    Code
    player.registerKeys(KeyInput.KEY_X, KeyInput.KEY_Y);
    player.setListenForKeyInput(true);

    2) The player opens either the chat or the console and, while typing some text, he presses one of the listened-for keys ('X' or 'Y' in the example).


    3) The plug-in is notified of those key strokes (PlayerKeyEvent).
    ____________________


    A) Is this expected behaviour?


    B) If yes, how the plug-in can detect that the key strokes are not 'played in-game' but as a textual entry and/or that player is in chat/console mode?