Thread: Aristotle

Page 1 of 2 12 LastLast
Results 1 to 10 of 11
  1. #1 Aristotle 
    Registered Member
    Join Date
    May 2017
    Posts
    124
    Thanks given
    41
    Thanks received
    43
    Rep Power
    56
    Attached image

    GitHub: https://github.com/tehnewb/Aristotle

    Aristotle is an open-source rs framework meant to increase RSPS server productivity and efficiency, but will hopefully assist beginners.
    It is kept open-source for the purpose of expecting involvement from the community.
    This project uses gradle for building, and for the dependencies, you can take a look at the build.gradle file in the root of this project to see what's being used.

    Reason

    The reason for Aristotle is to not only follow in the tracks of Apollo,
    but to keep the life of private servers alive with more than just matrix, project insanity, and dementhium.

    Mission

    The mission of Aristotle is to create a framework that allows programmers faster development time on content.
    To do this, I've made the design comprehensible and straight-forward as to avoid any confusion.
    Systems are also written in such a way to handle many situations and allow flexibility.



    Currently there is a 637 server embedded into this project as well to display use of Aristotle and for anyone who wishes to take from it. As Aristotle develops and improves, so will the embedded server.


    Spoiler for Starting:

    Starting the framework from your server
    Code:
      RSFramework.run(Application.class); // The Application.class should be substituted with your main class from your lowest level package
    Specifying the log level
    Code:
      /**
       * Place this piece of code in the main method BEFORE anything else.
       * Replace the "DEBUG" with your preferred log level
       */
      System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "DEBUG");


    Spoiler for Network:

    Binding to a port

    This is the only way to start the network from the framework
    Code:
      HandShakeCoder defaultCoder = ...
      RSFramework.bind(43594, defaultCoder);
    The network requires some kind of default coder to handle the encoding and decoding of the network messages. From that default coder, you can assign new coders using session.setCoder(RSCoder) This is also shown in the example below...
    Code:
    public class HandshakeCoder implements RSSessionCoder {
    	private static final byte JS5 = 15;
    	private static final byte LOGIN = 14;
    
    	@Override
    	public void decode(RSNetworkSession session, RSStream stream, List<Object> out) {
    		int request = stream.readUnsignedByte();
    		if (request == JS5) {
    			... // handling js5 variables and responses
    
    			session.setCoder(new CacheUpdateCoder());
    		} else if (request == LOGIN) {
    			... // handling login variables and responses
    			session.setCoder(new LoginCoder());
    		}
    	}
    
    	@Override
    	public RSStream encode(RSNetworkSession session, RSStream in) {
    		return in;
    	}
    
    }
    Implementing an RSSessionCoder

    Coders will handle the encoding and decoding of messages or frames. If there is no encoding done, you can just return the in parameter of the encode(RSNetworkSession, RSStream) method, otherwise return the encoded message as an RSStream. If you are sending any outgoing messages, they are to be added to the out list in the decode(RSNetworkSession, RSStream, List<Object>) method

    RSFrame and RSStream

    An RSFrame is just an extension of the RSStream class, but with an opcode and header. Below is shown an example of creating different RSFrames...
    Code:
    RSFrame varShortFrame = RSFrame.varShort(0); // header type is var_short with opcode of 0
    RSFrame varByteFrame = RSFrame.varByte(0); // header type is var_short with opcode of 0
    RSFrame standardFrame = RSFrame.standard(0); // header type is var_short with opcode of 0
    By usual definition, what makes a frame is a message with a corresponding operation code, so that is why it is called RSFrame.

    RSNetworkSession

    The RSNetworkSession holds the Channel, the RSSessionCoder, and other attributes for the network. As shown above, you can set the coder from the session variable passed through other coders, and this originates from the default coder that is usually set on application startup. The Channel of the session is just from the io.netty.channel package of netty 4.1.36 and will hold various methods to handle what happens with the channel. Attributes can be set to the session as well, which connects directly to the channel. These attributes are used for setting any values to the connection while the session is active. Below is an example of using the attributes and also writing to the session...
    Code:
    public class LoginCoder implements RSSessionCoder {
    
    	@Override
    	public void decode(RSNetworkSession session, RSStream in, List<Object> out) {
    		... // login variables and functionality
    	
    		Player player = new Player();
    		session.set("Player", player);
    	}
    	
    	... // other methods and functionality
    }
    
    /**
     * This may be a class you use for world request packet handling in the lobby
     */
    public class WorldRequest {
    	
    	// This is an example class not part of the framework
    	public void handleFrame(RSNetworkSession session, RSFrame frame) {
    		Player player = session.get("Player", Player.class); // getting the player object from the session for some reason
    		
    		RSFrame worldResponse = RSFrame.varShort(80);
    		worldResponse.writeByte(1);
    		worldResponse.writeShort(2);
    		worldResponse.writeInt(3);
    		...
    		
    		session.write(worldResponse);
    	}
    	
    }


    Spoiler for Resources:

    RSResource and RSResourceWorker

    The Resource class is meant to handle any file loading/saving or large calculations you might want done off the main thread. This can include loading account files, caches, xteas, or maybe creating dynamic maps/instances for your server. The queue() method in the Resource class is used to queue the resource to the RSResourceWorker class for loading. This is equivalent to calling RSFramework.queueResource(RSResource) Below is show an example of the RSResource in action...
    Code:
              @RequiredArgsConstructor
    public class AccountResource implements RSResource<Account> {
    
    	private final String username;
    
    	@Override
    	public Account load() throws Exception {
    		Account account;
    		
    		File file = new File("./accounts/" + username + ".json");
    		if (file.exists()) {
    			account = loadAccount();
    		} else {
    			account = createAccount();
    		}
    		
    		return account;
    	}
    
    	@Override
    	public void finish(Account account) {
    		loginAccount();
    	}
    
    }
    
    AccountResource resource = new AccountResource("CowK1ll3r");
    resource.queue(); // queue the resource for loading, and once it is finished
    				  // the finish(T) method will be called and you can handle the object from there


    Spoiler for Tick:

    The RSTick class is easy to use and can be added to the RSTickWorker in two different ways. You can call RSFramework.addTick(RSTick) or you can create a new RSTick and call the start() method of that tick. Below is an example of different tick usages...
    Code:
    /**
     * Fancy lambda. The tick has a delay of 1000ms and stops if the tick occurs 10
     * times
     */
    RSTick.of(t -> System.out.println("Hello, World: " + t.occurrences())).
    	.delay(1000)
    	.stopIf(RSTick.occurrs(10))
    	.start();
    
    /**
     * This is an example of the above functionality without all the fancy lambda
     */
    new RSTick() {
    
    	@Override
    	protected void tick() {
    		if (this.occurrences() == 10) {
    			stop();
    		}
    		System.out.println("Hello, World: " + this.occurrences());
    	}
    
    }.delay(1000).start();
    The stopPredicate of the tick is just a condition, that if passes as true, will stop the tick. So, let's say you want the tick to stop when a player reaches a certain location, you could use tick.stopIf(t -> p.getLocation().equals(new location(3222, 3222))) the [U]delay(long)[U] method can also be called from within the tick to change its delay even while it is running. The restart() method will just reset the occurences and the stop predicate.



    Spoiler for Events:

    The RSController annotation is expected for more uses in the future, but as of now, it's only for events

    RSController and RSEventMethod

    The RSController is an annotation meant for any class expected to handle events. The framework will search for any classes that have @RSController within the lowest level package from where you called RSFramework.run(Class<?>) If there is a method that has the @RSEventMethod, then that method will be registered as an 'invoker' that will also correspond to the event type within the parameters of that method. For example, if you were to have a class with this method: onUseItem(UseItemEvent event) then that method will be an invoker for the UseItemEvent class.

    To post an event of any kind, you use the [/CODE]RSFramework.post(Object)[/CODE] method. No events have to be registered to the framework, but there does have to be a method with that event as a parameter for anything to be invoked.

    Below is an example of using the event system...

    The controller
    Code:
    @RSController
    public class TestController {
    
    	@RSEventMethod
    	public void sayHello(TestHelloEvent event) {
    		System.out.println(event.message());
    	}
    
    }
    The event class
    Code:
    public record TestHelloEvent(String message) {}
    Posting the event
    Code:
    TestHelloEvent event = new TestHelloEvent("Hello World");
    RSFramework.post(event);



    Spoiler for Plugin:

    Loading Plugins

    Plugins allow for a modular-type project where you can keep content separated from the core project.

    Jar files are the only supported way for plugins and can be loaded as such...
    Code:
    	File dir = new File(ClassLoader.getSystemResource("MyPlugin.jar").toURI());
    	RSFramework.loadPlugin(dir);


    Spoiler for Media:

    Pathfinding


    Friends Chat


    Notes


    Skill targets


    Inventory and Equipment scripts


    Prayers and Quick Prayers




    Also gotta support my own 666 PvP Server...duh
    Last edited by Spooky; 09-07-2022 at 03:59 PM. Reason: Discord link removed, not allowed on project threads...
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Banned

    Join Date
    Jan 2012
    Posts
    191
    Thanks given
    45
    Thanks received
    87
    Rep Power
    0
    Very nice! Love seeing this kind of stuff, long live high revisions!
    Reply With Quote  
     

  4. #3  
    Donator

    .css's Avatar
    Join Date
    Dec 2018
    Age
    29
    Posts
    579
    Thanks given
    89
    Thanks received
    270
    Rep Power
    351
    +1 for open sourcing! I look forward to seeing the progress!
    Reply With Quote  
     

  5. #4  
    Registered Member
    Join Date
    May 2017
    Posts
    124
    Thanks given
    41
    Thanks received
    43
    Rep Power
    56
    Pathfinding is done using runescape's original BFS algorithm. This is credit to Kris and Greg's work, I just added onto it to make it fit the project. You can use the RSRouteBuilder to build the way a route works. You can add a reachRequest consumer to add what happens when the player reaches the end of the route. I would suggest setting the target of the route as well so you can retrieve it when handling the reach request.

    Example code for building a route to objects:
    Code:
    RSRouteBuilder builder = new RSRouteBuilder();
    builder.startingAt(player.getLocation());
    builder.endingAt(location);
    builder.target(locale);
    builder.destWidth(locale.getSizeX());
    builder.destHeight(locale.getSizeY());
    builder.objectRotation(locale.getRotation());
    builder.objectShape(locale.getType());
    builder.accessBitMask(locale.getAccessFlag());
    builder.reachRequest(new GameObjectReachRequest(player, locale.getData().getOptions()[index]));

    Reply With Quote  
     

  6. Thankful users:


  7. #5  
    Registered Member
    Spyr0's Avatar
    Join Date
    Oct 2012
    Age
    31
    Posts
    2,043
    Thanks given
    404
    Thanks received
    295
    Rep Power
    345
    Good luck with this project, I will be following and waiting for a release hopefully
    Reply With Quote  
     

  8. #6  
    Registered Member
    Join Date
    Jan 2015
    Posts
    502
    Thanks given
    15
    Thanks received
    95
    Rep Power
    45
    What Spyr0 said.

    Attached image
    Open-Source 2011 Remake

    Reply With Quote  
     

  9. #7  
    Registered Member
    Join Date
    May 2017
    Posts
    124
    Thanks given
    41
    Thanks received
    43
    Rep Power
    56
    Added a lot of things for this project:


    Spoiler for Framework Updates:

    Added the mechanics package: https://github.com/tehnewb/Aristotle...work/mechanics
    • Queue
      • RSScript
      • RSScriptQueue
      • RSQueueType

    • Timer
      • RSTimer
      • RSTimerQueue
      • RSTimerType
      • RSRoutineTimer
      • RSTimerRoutine


      The routine timer is mean to create non blocking & linear routines in such a way you can write scripts line by line just like this example:
      Code:
      waitFor(5); // waits 5 ticks
      walkTo(3222, 3222); // walks to the destination 3222, 3222
      msg("Hello, I have reached the coordinates finally); // only say this once walkTo has completed


    This class is an example of implementing a RSRoutineTimer.
    Code:
     @RequiredArgsConstructor
    public abstract class PlayerRoutineTimer extends RSRoutineTimer<Player> {
    
    	protected Player player;
    
    	@Override
    	public final void processSequence(Player player) {
    		this.player = player;
    
    		process();
    	}
    
    	/**
    	 * Processes this {@code PlayerTimer} for the given {@code player}.
    	 */
    	public abstract void process();
    
    	/**
    	 * Sends a message to the player.
    	 * 
    	 * @Param string    the string to send
    	 * @Param arguments the arguments within the string
    	 */
    	public PlayerRoutineTimer msg(String string, Object... arguments) {
    		this.addRoutine(new MessageRoutine(string, arguments));
    		return this;
    	}
    
    	/**
    	 * Forces the player to walk to the given coordinates.
    	 * 
    	 * @Param x the x coordinate
    	 * @Param y the y coordinate
    	 */
    	public PlayerRoutineTimer walkTo(int x, int y) {
    		this.addRoutine(new WalkToRoutine(x, y));
    		return this;
    	}
    
    	/**
    	 * Waits for the given {@code ticks} to pass before continuing.
    	 * 
    	 * @Param ticks the ticks to wait
    	 */
    	public PlayerRoutineTimer waitFor(int ticks) {
    		this.addRoutine(new WaitForRoutine(ticks));
    		return this;
    	}
    
    	/**
    	 * Teleports the player to the given destination.
    	 * 
    	 * @Param destination the destination to teleport to
    	 */
    	public PlayerRoutineTimer teleport(RSLocation destination) {
    		this.addRoutine(new TeleportRoutine(destination));
    		return this;
    	}
    
    	/**
    	 * Executes the given consumer
    	 */
    	public PlayerRoutineTimer andThen(Consumer<Player> consumer) {
    		this.addRoutine(new AndThenRoutine(consumer));
    		return this;
    	}
    
     @RequiredArgsConstructor
    	private class WalkToRoutine implements RSTimerRoutine<Player> {
    		private final int x, y;
    
    		private RSLocation destination;
    
    		@Override
    		public boolean run(Player player) {
    			if (destination == null) {
    				RSRouteBuilder builder = new RSRouteBuilder();
    				builder.startingAt(player.getLocation());
    				builder.endingAt(destination = new RSLocation(x, y, player.getLocation().getZ()));
    				LocationVariables.resetRoute(player);
    				player.getLocationVariables().setRoute(builder.findPath());
    			}
    			return !player.getLocation().equals(destination);
    		}
    	}
    
    	private record MessageRoutine(String string, Object... arguments) implements RSTimerRoutine<Player> {
    		@Override
    		public boolean run(Player player) {
    			player.sendMessage(string, arguments);
    			return false;
    		}
    	}
    
     @allargsConstructor
    	private class WaitForRoutine implements RSTimerRoutine<Player> {
    		private int ticksToWaitFor;
    
    		@Override
    		public boolean run(Player player) {
    			return --ticksToWaitFor > 0;
    		}
    	}
    
    	private record TeleportRoutine(RSLocation destination) implements RSTimerRoutine<Player> {
    		@Override
    		public boolean run(Player player) {
    			LocationVariables.resetRoute(player);
    			player.setLocation(destination);
    			player.getModel().registerFlag(new TeleportFlag());
    			return false;
    		}
    	}
    
    	private record AndThenRoutine(Consumer<Player> consumer) implements RSTimerRoutine<Player> {
    
    		@Override
    		public boolean run(Player player) {
    			consumer.accept(player);
    			return false;
    		}
    	}
    }



    Spoiler for 637 Updates:

    • Friends List
    • Ignore List
    • Clan Chat
    • Music Unlocking/Playing
    • Notes
    • Prayers and Quick prayers
    • Run Orb
    • Skill tab with target/xp setting
    • Inventory tab
    • Equipment tab with equipment view interface
    • Settings tab - Profanity Filter, Private messaging colors, Clan messaging colors


    Reply With Quote  
     

  10. #8  
    Registered Member
    Join Date
    Jan 2016
    Posts
    20
    Thanks given
    10
    Thanks received
    10
    Rep Power
    15
    In the video for "friends chat", when you go to send a private message to Albert, it displays as "To Dragonsevery" instead of the target user.
    Reply With Quote  
     

  11. #9  
    Registered Member
    Join Date
    May 2017
    Posts
    124
    Thanks given
    41
    Thanks received
    43
    Rep Power
    56
    Quote Originally Posted by Durbin View Post
    In the video for "friends chat", when you go to send a private message to Albert, it displays as "To Dragonsevery" instead of the target user.
    Thanks for pointing that out. Fixed it now
    Reply With Quote  
     

  12. #10  
    Donator

    Yuuji's Avatar
    Join Date
    Feb 2012
    Posts
    678
    Thanks given
    232
    Thanks received
    153
    Rep Power
    197
    Mind linking the client & cache you're using with this? Can't seem to find a 637 client/cache anywhere

    Attached image
    Attached image
    Reply With Quote  
     

Page 1 of 2 12 LastLast

Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Tags for this Thread

View Tag Cloud

Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •