Giter VIP home page Giter VIP logo

orion-core's People

Contributors

axiskriel avatar hakusaro avatar ijwu avatar ivanbiljan avatar kevzhao2 avatar marioe avatar patrikkk avatar signaturebeef avatar tylerjwatson avatar whitexz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

orion-core's Issues

Orion Framework: Command service

implement a command service which handles commands with parameters that are either invoked by players, the console, or any UI frontend running in Orion.

The basic spec is as follows:

  1. Design an ICommandStreamService (shared) whose job it is to keep the list of commands, and facilitate the insertion of command handlers at any place in the handler stack, handle the deserialisation of command parameters, and invoke each handler in the list
  2. Design an ICommandService whose job it is to yield commands from their method (up to the implementation), and yield the delegates to to the ICommandStreamService

A command service implementation idea is listed below:

  • AttributeCommandService: Yields command from attributes placed on instance methods:

    [Command("/invsee {player} {-restore:flag}")]
    public CommandResult InvseeCommand(IPlayer player, bool? restore = null)
    {
    }

ObjectStream output

Commands must not write to Console or Player, instead must write to an object stream passed to the command in its parameters. This is to ensure that objects written as output from the commands are always formatted in a consistent manner.

A command may choose to output any object to the output stream, and they are formatted according to the rules of the UI environment which invokes the command. A command may output more than one object to the output stream, which may include one or more exceptions.

For example, a plugin may output an IEnumerable<>, which will format as a text table in the console, comma-separated list in the game itself, a HTML table in the web UI, or a JSON array as a REST call. An exception written to the object stream may format as red text in the console, or a callout in HTML, etc.

Any .NET type may be written to the object stream, however complex types will be coalesced to string before output; implement .ToString() if you want to summarize a human-friendly representation of a custom object.

Orion v1.4 Development Progress

This issue will serve as a tracker for Orion progress (under the v1.4 branch). It will also indicate how "ready" Orion is in terms of developing against it. A large portion of the pre-development milestones have been knocked out, which means that it is pretty much okay to start developing against Orion.

The concurrent development milestones can be completed at the same time as developing against Orion, as it involves supplementing Orion with missing packet definitions, event definitions, etc.

Pre-development will be done mostly directly onto the v1.4 branch. Once there is enough developer bandwidth (besides me), we can begin migrating to a better workflow involving new branches and pull requests.

Pre-Development Milestones

  • Service and plugin architecture
    • Binding and rebinding services
    • Binding ILogger and Lazy<T>
    • Loading and "unloading" plugins
  • Event architecture
    • Priority-based event handlers
    • Auto-ignoring canceled events
    • Logging
    • Aggregated events and event handlers under OrionKernel
  • Packet architecture
    • Efficient struct-based packets
    • Efficient struct-based modules
    • Packet event handling in OrionPlayerService
  • Starting Terraria abstractions
    • IItem and IItemService
    • INpc and INpcService
    • IPlayer and IPlayerService
    • Projectile abstraction (#57)
    • Tile abstraction (#58)
    • World abstraction (#61)

Concurrent Development Milestones

  • Packet definitions (#65)
    • Module definitions (1 of 11 completed)
  • Additional event definitions
  • Augment Terraria abstractions
    • Chest abstraction
    • Sign abstraction
    • Tile entity abstraction

Terraria Packet Definitions

Provide definitions for each Terraria packet (names are WIP):

  • 1: ClientConnectPacket
  • 2: ServerDisconnectPacket
  • 3: ServerIndexPacket
  • 4: PlayerDataPacket
  • 5: PlayerInventoryPacket
  • 6: PlayerJoinPacket
  • 7: WorldInfoPacket
  • 8: SectionRequestPacket
  • 9: ClientStatusPacket
  • 10: SectionInfoPacket
  • 11: SectionFramesPacket
  • 12: PlayerSpawnPacket
  • 13: PlayerInfoPacket
  • 14: PlayerActivityPacket
  • 16: PlayerHealthPacket
  • 17: TileModifyPacket
  • 18: WorldTimePacket
  • 19: DoorTogglePacket
  • 20: TileSquarePacket
  • 21: ItemInfoPacket
  • 22: ItemOwnerPacket
  • 23: NpcInfoPacket
  • 27: ProjectileInfoPacket
  • 28: NpcDamagePacket
  • 29: ProjectileRemovePacket
  • 30: PlayerPvpPacket
  • 31: ChestOpenPacket
  • 32: ChestInventoryPacket
  • 33: ChestInfoPacket
  • 34: ChestModifyPacket
  • 35: PlayerHealthEffectPacket
  • 36: PlayerZonesPacket
  • 37: ServerPasswordedPacket
  • 38: ClientPasswordPacket
  • 39: ItemDisownPacket
  • 40: PlayerTownNpcPacket
  • 41: PlayerAnimationPacket
  • 42: PlayerManaPacket
  • 43: PlayerManaEffectPacket
  • 45: PlayerTeamPacket
  • 46: SignReadPacket
  • 47: SignInfoPacket
  • 48: TileLiquidPacket
  • 49: PlayerEnterPacket
  • 50: PlayerBuffsPacket
  • 51: EntityEffectPacket
  • 52: ObjectUnlockPacket
  • 53: NpcBuffPacket
  • 54: NpcBuffsPacket
  • 55: PlayerBuffPacket
  • 56: NpcNamePacket
  • 57: WorldBiomesPacket
  • 58: PlayerMusicPacket
  • 59: WireActivatePacket
  • 60: NpcHomePacket
  • 61: WorldSummonPacket
  • 62: PlayerDodgePacket
  • 63: BlockPaintPacket
  • 64: WallPaintPacket
  • 65: EntityTeleportPacket
  • 66: PlayerHealPacket
  • 68: ClientUuidPacket
  • 69: ChestNamePacket
  • 70: NpcCatchPacket
  • 71: NpcReleasePacket
  • 72: NpcMerchantPacket
  • 73: PlayerTeleportPacket
  • 74: AnglerQuestPacket
  • 75: PlayerCompleteAnglerQuestPacket
  • 76: PlayerAnglerQuestsPacket
  • 77: TileAnimationPacket
  • 78: InvasionProgressPacket
  • 79: ObjectPlacePacket
  • 80: PlayerChestPacket
  • 81: ServerCombatNumberPacket
  • 82: ModulePacket<>
  • 83: NpcKillsPacket
  • 84: PlayerStealthPacket
  • 85: PlayerQuickStackPacket
  • 86: TileEntityInfoPacket
  • 87: TileEntityPlacePacket
  • 88: ItemTweakPacket
  • 89: ItemFrameInfoPacket
  • 90: InstancedItemInfoPacket
  • 91: NpcEmotePacket
  • 92: NpcStealCoinsPacket
  • 95: ProjectileRemoveIndexPacket
  • 96: PlayerPortalPacket
  • 97: NpcIdKilledPacket
  • 98: EventOccurredPacket
  • 99: MinionTargetPositionPacket
  • 100: NpcPortalPacket
  • 101: PillarShieldStrengthsPacket
  • 102: PlayerNebulaPacket
  • 103: MoonLordCountdownPacket
  • 104: NpcShopInventoryPacket
  • 105: GemLockTogglePacket
  • 106: ServerSmokePacket
  • 107: ServerChatPacket
  • 108: ProjectileCannonPacket
  • 109: WireOperationPacket
  • 110: PlayerConsumeItemsPacket
  • 111: BirthdayPartyTogglePacket
  • 112: TreeGrowEffectPacket
  • 113: OldOnesArmyStartPacket
  • 114: OldOnesArmyEndPacket
  • 115: MinionTargetNpcPacket
  • 116: OldOnesArmyInfoPacket
  • 117: PlayerHurtPacket
  • 118: PlayerKillPacket
  • 119: ServerCombatTextPacket
  • 120: PlayerEmojiPacket
  • 121: MannequinInventoryPacket
  • 122: TileEntityInteractionPacket
  • 123: WeaponsRackInfoPacket
  • 124: HatRackInventoryPacket
  • 125: BlockBreakingPacket
  • 126: NpcRevengeInfoPacket
  • 127: NpcRemoveRevengePacket
  • 128: GolfBallPacket
  • 129: ServerConnectedPacket
  • 130: NpcFishPacket
  • 131: NpcImmunityPacket
  • 132: ServerSoundPacket
  • 133: FoodPlatterInfoPacket
  • 134: PlayerLuckPacket
  • 135: PlayerDeadPacket
  • 136: NpcCavernMonstersPacket
  • 137: NpcRemoveBuffPacket
  • 139: PlayerHostPacket

Discussion: Current State of Orion

Since I've pushed a ton of stuff to the reboot branch, I want to recap what's been done there.

Orion's goal is to act as an intermediary layer between OTAPI/Terraria and TShock/other plugins. The way in which this is done is by providing interfaces such as INpc and INpcService to consumers such as TShock. There are three main reasons for this:

  • Testability. With interfaces, it's much easier to mock, say, a Terraria NPC than before. This should make all plugins a lot easier to test and less buggy.
  • Extensibility. A custom NPCs plugin could create its own implementation of INpc by creating its own INpcService and allow NPCs to have extra features.
  • Compatibility. These interfaces shield customers from any changes in the underlying OTAPI/Terraria server code. Granted, in cases of extreme change, we'll still need to modify the interfaces and break compatibility, but this is at least a step in the right direction.

To create a service, you should create an interface that inherits from IService and an implementation that inherits from OrionService and implements your interface. The Author, Name, and Version properties can be overridden as necessary.

public interface ICommandService : IService {
    void ExecuteCommand(string input);
}

internal class TShockCommandService : OrionService, ICommandService {
    public void ExecuteCommand(string input) { }
}

To create a plugin, your implementation should inherit from OrionPlugin. It isn't necessary to create a plugin interface, but you could do that if you wanted to. Your constructor should include all of the plugins and services you'll need, as they'll be injected for you.

public class WorldEditPlugin : OrionPlugin {
    public override string Author => "Kevin";
    public override string Name => "WorldEdit";

    private readonly IWorldService _worldService;

    public WorldEditPlugin(OrionKernel kernel, IWorldService worldService) : base(kernel) {
        _worldService = worldService ?? throw new ArgumentNullException(nameof(worldService));
    }
}

To register a hook, just use += on the relevant HookHandlerCollection<> with a valid handler. This is thread-safe since HookHandlerCollection<> is immutable.

_worldService.SavingWorld += SavingWorldHandler

...

[HookHandler(HookPriority.Lowest)]
private void SavingWorldHandler(object sender, SavingWorldEventArgs args) {
}

Logging is handled via Serilog. To log something, just access the static Log class:

Log.Verbose("Verbose message");
Log.Debug("Debug message");
Log.Information("Information message");
Log.Warning("Warning message");
Log.Error("Error message");
Log.Fatal("Fatal message");

By default, the Orion launcher sinks this log to the console and a daily rolling file under the logs/ directory.


Listed below is the functionality that Orion currently has. I don't think the services that we offer are going to change any time soon.

  • IItemService: access IItem instances, item-related hooks, and item-related methods (SpawnItem, etc.).
  • INetworkService: access IClient instances, network-related hooks, and network-related methods (BroadcastPacket, etc.). There is an entire type-safe packet library implemented under Orion.Networking.Packets to facilitate usage.
  • INpcService: access INpc instances, NPC-related hooks, and NPC-related methods (SpawnNpc, etc.).
  • IPlayerService: access IPlayer instances and player-related hooks.
  • IProjectileService: access IProjectile instances, projectile-related hooks, and projectile-related methods (SpawnProjectile, etc.).
  • IChestService: access IChest instances and chest-related methods (AddChest, GetChest, etc.).
  • ISignService: access ISign instances and sign-related methods (AddSign, GetSign, etc.).
  • IWorldService access Tile instances, world-related hooks, and world-related methods (Save, etc.).

In addition, all objects above are annotatable, allowing users to get or set annotations for each instance. This makes it easy for these objects to be extended.

Orion will not be responsible for providing commands, configurations, or users, groups, or permissions. This is to be handled by plugins such as TShock, and allows Orion to remain as light-weight as possible.


If you have any comments or suggestions, please respond with them.

Framework - OrionModule transparent configuration system

Rationale

Moving to a modular system in orion paves the way for transparent configuration, so we may as well use it. Configuration is a pain point for current plugin developers.

The proposed architecture makes it possible for plugins to store their configs in a clean and consistent fashion, without the developer ever having to care about the physical files themselves; all they need to care about is their config class in their code is full of human configured values.

Architecture

I propose that configuration management be perfomed by Orion itself, and not by plugins. If an Orion module is to have a configuration, it must provide a configuation class inheriting from OrionModuleConfiguration, otherwise no configuration for the module is assumed.

If the configuration doesn't exist, Orion is to create one via the interface, with default values in the class.

This class is to contain regular properties full of arrays and everything that the module needs to configure itself from a human perspective, and Orion fetches configurations during its init/reload phase and provides an instance of the deserialized configuration class to the instance via the OrionModuleBase constructor which could have a OrionModuleConfiguraion config parameter. Alternatively, OrionModuleBase could have a virtual GetConfiguration<TConfiguration>() where TConfiguration is the type of class the module has registered.

OrionModuleConfigurationBase is to haveSave(), Reload() and any other sensible methods which will tell orion to manipulate config.

Configuration is to come from an IConfigurationProvider framework implementation discussed in #12. It may write to JSON, it may write to XML, it may write to SQL, it may write to REST. it could, in effect, be anything.

Pathing

TSAPI shall be modified, with the old Environment.CurrentDirectory assuming code removed in lieu of a smarter system, particularly for Linux servers which expect configuration to be in /etc/. There must also be a shared plugins directory to help shared hosting providers run only one copy of plugin files.

File Format

TBD

Result

Orion plugins only have to write a class full of properties for configuration, and Orion takes care of the rest.

Others

TODO

Service framework: AAA

Authentication, Authorization and Accounting service, which takes care of user accounts, authroization, groups, and permissions.

Namespace and type naming collisions

There are a few instances of shared namespace and type names:

  • class Orion and namespace Orion
  • class Item and namespaces Orion.Entities.Item, Orion.Events.Item
  • class Npc and namespaces Orion.Entities.Npc, Orion.Events.Npc
  • class Player and namespaces Orion.Entities.Player, Orion.Events.Player
  • class Projectile and namespaces Orion.Entities.Projectile, Orion.Events.Projectile

This could lead to a few annoyances later on, and should probably be fixed now. One solution would be to pluralize Orion.Entities.<EntityName> (and place the events in there too, or pluralize that as well). I'm not sure how we should deal with Orion.Orion, though.

Bans

How would we like bans to work?
I believe there was a brief discussion in Slack involving a suggestion to simply have an 'enabled/disabled' flag on each account.
Plugins simply modify this value to 'ban' a user and track any other information they may need independently (e.g., banned/disabled datetime, reason, who banned the account).

Suggestions? Feedback?

Implement missing hooks, if any

In OTAPI we expect there to be missing and/or differing hooks. These will need to be implemented in order to not lose features in the shift to Orion

Externalise strings

Over the years we have had many requests for TShock to be translated, as well as offers from translators to do so. However, due to the nature of the codebase (i.e., hardcoded strings), this is a difficult task.

I propose we make use of Visual Studio's built in resx file support (read more here) to help remedy this issue.

Orion Internal Architecture Proposal

Rationale

Orion at the moment seems to be largely a copy-paste of TShock's design patterns. Not to discredit the design as you have to start somewhere, thinking about the architecture I would really like to initiate the change to a modular design.

It's vital that chunks of Orion be self-contained, as they may be swapped out for anything else.

Structure

I propose that modules in Orion be self-contained classes inheriting from an abstract OrionModuleBase class which essentially just defines a single Run() method which the core will call to run it. OrionModuleBase implements IDisposable, and the module must be responsible for destroying its own functionality, and the server must be able to run without it enabled; it just misses that functionality:

  • Modules can now even live in separate assemblies
  • Modules are interfaces, whose implementations may be swapped out at any point and everything goes on its merry way
    • On this, as long as the interfaces don't change, APIVersion tags will need to be ticked less and everyone will be happy
  • Module sets up its own hooks, everything it needs to survive and function as expected
  • Module tears down its its own hooks and everything it needed to function
  • Modules may interact with other modules by Orion's core.Get<TModule>() method which will return the instance of module for that type, beware of nulls.

Initialization

  1. Modules should be collected by Orion which are marked with the [OrionModule("ModuleName", "Author", {order})] attribute, and instantiated when it runs.
  2. Orion initializes all modules by the author, and calls the abstract OrionModuleBase.Run() method
  3. Programs then brings the awesome

TShock 4 -> 5 Feature Map

This is a project I discussed with @tylerjwatson. Effectively, I'm going through the entire TShock 4 codebase and identifying key features, commands, subsystems, etc. and dividing them up in a table to determine where they should go in TShock 5 and Orion.

Because the wiki doesn't have any way to send notifications to Slack, I'm creating an issue here to track my progress as I work to enumerate through features. In addition, I plan on asking for input directly when something comes into question (should feature X or Y be in Orion or in TShock 5?).

Very spare, but I hope to make significant progress in the next week or so to help guide implementation of features in Orion that need to be done before TShock 5 can start being designed around Orion.

TShock 4 Feature In Orion? Service def. in Orion? In TShock 5? Status / Comment
Rest API โœ”๏ธŽ โœ”๏ธŽ Not complete. See #6. Many routes will be added in both TShock 5 and Orion, but the core implementation will be in Orion. TShock will add routes as necessary (and the services it implements will too).
Log system โœ”๏ธŽ Not started. Presumably logging will be handled by an Orion service and TShock will deliver its messages to that service. See #19. Almost all log related config options should be removed from TShock, except maybe a binary "send logs to Orion log service" option.
Bans โœ”๏ธŽ โœ”๏ธŽ To be determined. Not sure if this is supposed to be in AAA or not. If in AAA, not sure if it's supposed to handle user facing entry points or if another plugin should be exposing AAA.
Warps โœ”๏ธŽ Not migrated. Warp subsystem likely handled entirely in TShock 5, but could be removed and split into another plugin.
Regions โœ”๏ธŽ Not migrated. Region subsystem likely handled entirely in TShock 5, but could be removed and split into another plugin.
Backups ? ? ? Not sure if this subsystem should be in TShock 5, but will likely remain in TShock 5.
Groups โœ”๏ธŽ โœ”๏ธŽ Not completed. Should be implemented in AAA, but unclear if user facing entry points should be in Orion or if TShock should implement them (commands, for example).
Users โœ”๏ธŽ โœ”๏ธŽ Not completed. Should be implemented in AAA, but unclear if user facing entry points should be in Orion or if TShock should implement them (commands, for example).
Item bans โœ”๏ธŽ Not migrated. Item bans subsystem likely handled entirely in TShock 5, but could be removed and split into another plugin.
Projectile bans โœ”๏ธŽ Not migrated. Projectile ban subsystem likely handled entirely in TShock 5, but could be removed and split into another plugin.
Tile bans โœ”๏ธŽ Not migrated. Tile ban subsystem likely handled entirely in TShock 5, but could be removed and split into another plugin.
Remembered position manager โœ”๏ธŽ Not migrated. Remembered pos manager likely handled in TShock 5, but should probably be moved into another plugin.
Server side characters โœ”๏ธŽ Not migrated. SSC likely handled in TShock 5. Could be a separate plugin, but also really hard to do and really easy to screw up.
Stat tracker โœ”๏ธŽ Not started. Likely handled in Orion as a service. To be completely removed in TShock 5.
GeoIP โœ”๏ธŽ Not migrated. Likely handled in TShock 5. Could be a separate plugin, but recent rewrites by Enerdy actually have it working.
Database ? ? Not clear as to where plugins can store arbitrary data.
Whitelist โœ”๏ธŽ Not migrated. Likely handled in TShock 5.
Config ? ? ? Unclear where arbitrary config files are read/written and how this correlates in TShock 5.
Misc random config file settings in TShock โœ”๏ธŽ Not migrated. Most will make it into TShock 5 or be split out into plugins.

Proper Plugin Sandboxing

I don't know if 'sandboxing' is the right term, but one thing that's been an issue in TShock is that once plugins are loaded they're stuck. You can't unload nor reload a plugin. Since the method we use to load plugins has been to load the plugin types out of third party assemblies into the TShock AppDomain we can't really unload or reload them.

This issue highlights development made towards the progress of loading plugins in a way which allows their types to be disposed of and reloaded. The way to do this would be to load the types into a separate AppDomain. This can be done manually or facilitated with the System.AddIn namespace.

[RFC] Service framework: External definitions

Until now, Orion only allows service definitions internal to its own assembly. They are defined by us and essentially hard-coded. The injector doesn't know how to bind interfaces it doesn't know about.

It's time to have a discussion about extensibility to the service mechanism which will allow the flexibility to create "foreign" service types externally, from assemblies in the plugins directory in the same way plugins are harvested.

User story: custom services

As the author of SEconomy, a plugin that provides a facility (or service) to other plugins and extensions, I should have the ability to define my own services in which will be injected into my own plugin, and others.

Consider a hypothetical SEconomy service definition externally in Orion:

public interface IWorldEconomyService : IService
{
}

In this design, I define my own world economy service to Orion which is contained in my plugin assembly. The assembly has its own default implementation which SEconomy will use, but other people may choose to override the service and provide their own world economy.

As long as they implement IWorldEconomyService, there is nothing stoping plugins from extending other plugins' functionality.

Consider a hypothetical SEconomy plugin:

public class EXPPlugin(Orion orion, ICurrency<ExpCurrency> currencyService, 
        IWorldEconomyService worldEconomy) : base(orion)
{
    ...
}

In this example, IWorldEconomyService by default shall point to its own internal implementation of world economy, however doesn't have to. The same semantics shall apply to ICurrency<>, or any service definition.

Database - [UserInventory] structure

Rationale

Note: Most of this is TBD because I don't understand SSC mechanisms yet

TShock's SSC mechanism is largely unknown, but in the very least we should look to save people's items in [UserInventory] and [UserInventorySet] tables.

Grouping sets of people's inventories will allow keeping a history of peoples items. For example, a plugin may choose to 'snapshot' an inventory which are saved as an [InventorySet], or a plugin may create an arbitrary [InventorySet] which may be applied to any account at any point in the game.

Structure

TBD

Patch CVE-2018-1000210.

We're getting a security alert for this CVE: https://nvd.nist.gov/vuln/detail/CVE-2018-1000210

The patch seems to be a trivial update to packages.config:

<package id="YamlDotNet" version="5.0.0" />

This is a high priority issue because we're going to be emailed about it until it gets fixed. Coincidentally, this is also a great hacktoberfest issue!


Hello Hacktoberfesters! If you're looking for something to do please patch this. It's really easy.

Discussion: How to handle events

Currently, there are EventHandlerCollection<TEventArgs> properties on all of the services. To register an event, you'd do something like the following:

private readonly Lazy<PlayerService> _playerService;

// ...

_playerService.Value.PlayerJoin.RegisterHandler(PlayerJoinHandler, Log);

// ...

[EventHandler(EventPriority.Monitor)]
public void PlayerJoinHandler(object? sender, PlayerJoinEventArgs e) {
    Log.Debug("{Player} joined", e.Player);
}

However, another possible way to register events could be like the following:

Kernel.RegisterEvents(this);

// ...

[EventHandler(EventPriority.Monitor)]
public void OnPlayerJoin(PlayerJoinEventArgs e) {
    Log.Debug("{Player} joined", e.Player);
}

[EventHandler(EventPriority.Monitor)]
public void OnPlayerQuit(PlayerQuitEventArgs e) {
    Log.Debug("{Player} quit", e.Player);
}

The idea is that OrionKernel.RegisterEvents will take all methods from the given object, filtering using the ones with EventHandlerAttribute annotating them, and register them automatically. There would be no requirement to define any EventHandlerCollections anywhere, they'd just get aggregated in the kernel. Additionally, to invoke the events, you would just do the following:

Kernel.InvokeEvent(new PlayerJoinEventArgs(player));
Kernel.InvokeEvent(new PlayerQuitEventArgs(player));

TL:DR; first approach is explicit, second approach is more similar to Bukkit's. What are your thoughts on these two approaches?

Database - [Permission] structure

Rationale

TShock's permission system is made up of a comma-separated list of groups, using SQL only as a storage engine and not what it's supposed to be used for. Most of the performance problems with the AAA system can be resolved by using proper schema.

Structure

  • [Permission] table:
    • ID - primary Key
    • Name - permission name
  • [GroupHasPermission] joiner table:
    • PermissionID - Primary key
    • GroupID - Primary key
  • [UserPermission] table:
    • UserFK - Foreign key to [User]
    • PermissionFK - Foreign key to [Permission]
    • IsNegated - Indicates whether a permission is to be explicitly negated

Precedence rules

HasPermission follows these rules:

  1. [User] has an explicit [Permission], and if IsNegated immediately returns the value of IsNegated
  2. For each [Group] assigned to [User], if the [Group] has permission then immediately returns true, else it continues on to the next group
  3. Finally, returns false if no groups contain the permission

Notes

  • Plugins should have their own permissions which Orion shall iterate over, and insert into if necessary during Orion's init phase
  • [Permission] should be many-to-many with [Group] which in turn is many-to-many with [User](pending #8)
    • One [Group] may have many [Permissions], in turn, one [Permission] may have many [Groups]
  • May be cached on Orion's init system, though shouldn't impact too much SQL with proper indexing

Orion Framework: Internal Message Queue

Event handling, in its current form, relies heavily on the C# event object. This is seriously limited in that services may not define prioritization or handling order.

An internal message queue would allow for all services to write events to the queue and allow all other services to receive and respond to messages in a pub-sub pattern.

What blocks TShock 5?

In one of many discussions with Wolfje, I pointed out that it would be worth developing TShock 5 along side Orion as fast as possible to get momentum going to answer questions like "what actually needs to be in Orion?" The general feedback I got was that development on TShock 5 shouldn't start until a lot of the underlying Orion structure is done, but this poses a problem: how do you develop a framework for a plugin with requirements that don't exist?

To start, I've created a label called "Blocks TShock 5," which should go on issues that completely block starting development on TShock 5. In other words, these are issues that, without being completed, we can't even have a stupid plugin that initializes and says "Hi I'm TShock 5" on Orion without it being completely useless.

Issues that fall under this scope are core, critical bits of functionality like commands, logging and how to properly setup and define an Orion plugin. I'm going to be making issues for things like this and continuing to ask for direction here.

Why? Right now, as a TShock developer who hasn't kept up with Orion development fully, it's still basically impossible for me to contribute useful code to the project because it's unclear what needs to be done and how the design works. I know how it works in an abstract sense but I can't with concrete 100% certainty say where I should start. I'd say this goes for anyone who hasn't submitted pull requests to Orion already. In other words, Orion development is limited to a very small subset of developers, all of which don't necessarily have all the free time in the world to keep development going during slow periods.

Some high level goals also get attached to this issue:

  • Update the documentation so that new developers can start working on things without having to interview every Orion team developer to figure out how Orion works.
  • Create small, bite size issues & stories with a clear focus so that new developers can start working on things faster. Don't leave people guessing as to what needs to be done: define it.
  • Create a process guide on how to properly implement parts of Orion and how to create service definitions. Make a checklist for what needs to be modified, how tests work, etc.
  • Provide clear examples of what goes in Orion and what doesn't. Make it stupid easy to determine if something should be in Orion or if it should be in a plugin.
  • Document how to actually write a plugin for Orion. Yes, the documentation will change. Yes, the spec isn't complete. But it's pointless to have everything built months in advance and undocumented if it isn't going to change from now to release. If it's going to change from now to release, change it and document it. Make it so that Orion can "go live" sooner by having a nice, well defined, up to date set of documentation and examples to start writing your own plugins.
  • Encourage development and answer questions. If you don't answer questions asked by people on issues, then Orion won't go anywhere. If question keeps getting repeated this is a sign that it needs to be documented on the wiki or in some other location.
  • Give examples of best practices. If our end goal is to not have service implementations in Orion, service implementations shouldn't be in Orion. Full stop. Yes, it's convenient for development, but it does nothing to help clarify what's going on or what goes where. It's confusing.

If Orion never gets TShock 5 running on it, it will be a waste. If a we keep having to update the Terraria Server API because of new Terraria releases while Orion development crawls along, Orion is a waste.

Why am I making this issue? Because it's not clear to me, looking at the issue list and reading the current wiki, where I can even dive in and help. I've certainly asked a lot of questions and gotten a basic grasp, but I don't even know where to start. If I don't know where to start, then I doubt many other people outside of the core group here do.

Right now it's pretty clear that the people who can start working on fixing these problems are: @MarioE, @tylerjwatson, @WhiTexz, and @DeathCradle. These fundamental issues need to be resolved because if I start contributing right now, it's going to be the blind leading the blind.

Prepare a presentation on Orion API

This issue is to track a presentation to other stakeholders what orion actually is, and to go through an end-to-end use case for why some of Orion's design decisions are the way they are, and to discuss the merits between them

Outcomes of the presentation:

  1. A clear consensus on what Orion actually is, and what it means for Terraria (OTAPI)
  2. A clear consensus on what Orion is not
  3. A clear consensus on the development strategy for Orion so far (TDD)
  4. A clear consensus on what terraria features mean and how they map to Orion services

Once the above has been achieved, it's then possible to document it out.

Materials:

  • A layer-diagram illustrating where Orion fits between Terraria and server modules (for point 1)

Notes:

  • Orion is an abstraction layer with the goal of hiding as much of Terraria's internal mechanisms away from server/software engineers as possible.
  • Orion makes the "only worry about what you can control" mantra possible:
    • Remove the need to interact with the Terraria statics
    • Remove the need to tick API versions as Orion takes care of the binary changes in Terraria
    • Provide Terraria features in an abstracted implementation
    • Goal is for server owners to not worry about low-level Terraria mechanisms
  • Orion is also a container, in that it is responsible for running and managing instances of the Terraria server
    • Orion itself is a class library, but has front-end projects which bootstrap it (Console, Windows Services etc)

Orion Architecture:

  • Orion is built with the inversion-of-control principle:
    • Only worry about what you need to know in the API; don't worry about the rest of it or how it's implemented
    • Don't worry about dependencies, just inject them
    • Everything is interfaced; don't worry about the implementations

More to come as I think of them

REST API v3

TShock's REST API v2 is out for quite some time now and it would be nice to have a next version. This gives room to fix some inconsistencies, remove duplication, fix issues and add features.

For example purposes, I will use 127.0.0.1 for the host and 7878 for the REST port. Also, because JSON does not officially support comments, I "faked" the comments.

Consistency

Base URL

One issue we currently face is that you have to use v1 for some endpoints and for some other endpoints v2. In v3 everything should be called from http://127.0.0.1:7878/v3/.

Keys

Keys MUST be lower_under.

Values

A value SHOULD NOT contain multiple values. buffs from REST v2 is a good example of how it should not be done.

{
    "//": "...",
    "buffs": "147, 86, 158, 146, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0"
}

Dates

All dates SHOULD be available as specified in ISO 8601.

Complete date plus hours and minutes:
YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)

โ€” http://www.w3.org/TR/NOTE-datetime

Security

GET can expose sensitive data. And besides,

the convention has been established that the GET and HEAD methods SHOULD NOT have the significance of taking an action other than retrieval. These methods ought to be considered "safe".

โ€” http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1

Like in v1 and v2, the token should not be in the URL.

Usernames, passwords, session tokens, and API keys should not appear in the URL, as this can be captured in web server logs, which makes them intrinsically valuable.

โ€” https://www.owasp.org/index.php/REST_Security_Cheat_Sheet

Endpoints

Tokens

Generating a token

Deprecates: /token/create
http://127.0.0.1:7878/v3/token/generate
data:

username = 'restuser'
password = 'restpass'

Example response:

{
    "status": 201,
    "response": "Successfully generated token.",
    "data": {
        "token": "5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347",
        "expiration_date": "2015-7-24T13:39Z"
    }
}

Validating a token

Deprecates: /tokentest
http://127.0.0.1:7878/v3/token/validate
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "response": "Token is valid.",
    "data": {
        "token": "5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347",
        "expiration_date": "2015-7-24T13:39Z"
    }
}

Server

Information

Deprecates: /v2/status, /v2/server/status
http://127.0.0.1:7878/v3/server/info
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "data": {
        "name": "TerraServer",
        "host": "127.0.0.1",
        "port": "7777",
        "software": {
            "name": "tshock",
            "version": "4.4.0"
        }
    }
}

Executing a command

Deprecates: /v2/server/rawcmd, /v2/world/butcher, /world/meteor, /world/bloodmoon/{bool}, /v2/players/kick, /v2/players/kill, /v2/players/mute, /v2/players/unmute, /v2/world/save, /v2/server/broadcast
http://127.0.0.1:7878/v3/server/execute-command
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
command = 'time noon'

Example response:

{
    "status": 200,
    "response": "Server set the time to 12:00."
}

Changing server password

http://127.0.0.1:7878/v3/server/update-password
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
password = '123123'

Example response:

{
    "status": 200,
    "response": "Successfully changed server password."
}

Shutting the server down

Deprecates: /v2/server/off
http://127.0.0.1:7878/v3/server/shut-down
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
save = false // Optional; default true

Example response:

{
    "status": 200,
    "response": "Server shut down. World not saved."
}

Starting the server up

New feature
http://127.0.0.1:7878/v3/server/start-up
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
port = 8888 // Optional; default 7777

Example response:

{
    "status": 200
}

World

Information

Deprecates: /world/read, /v2/server/status
http://127.0.0.1:7878/v3/world
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "data": {
        "id": 18624254254,
        "name": "World 3",
        "size": {
            "type": "medium",
            "width": 6400,
            "height": 1800
        },
        "mode": "expert",
        "creation_date": "2015-7-24T13:39Z",
        "//": "In what format is the time??",
        "time": "42149",
        "is_day": true,
        "is_bloodmoon": false,
        "//": "TODO: Improve invasionsize.",
        "invasionsize": 0
    }
}

Auto-saving

Deprecates: /v2/world/autosave/state/{bool}
http://127.0.0.1:7878/v3/world/auto-save
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
mode = false // Optional; default true

Example response:

{
    "status": 200,
    "response": "Successfully set auto-save to true."
}

Groups

Group information

Deprecates: /v2/groups/list, /v2/groups/read
http://127.0.0.1:7878/v3/groups
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "response": "Successfully fetched 8 groups.",
    "data": {
        "groups": [
            {
                "name": "default",
                "parent": "guest",
                "rgb_chat_color": [
                    255,
                    255,
                    255
                ],
                "permissions": [
                    "tshock.reservedslot"
                ],
                "negatedpermissions": [],
                "totalpermissions": [
                    "tshock.reservedslot",
                    "tshock.warp",
                    "// ...",
                    "tshock.canchat"
                ]
            },
            "// ..."
        ]
    }
}

Create group

Deprecates: /v2/groups/create
http://127.0.0.1:7878/v3/group/create
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
name = 'Team Penguin'
prefix = '(Team Penguin)'
suffix = null
parent_type = 'id' // Optional; defaults to "name"; options: id, name
parent_group = 23
permissions = [
    'tshock.tp.self',
    'tshock.tp.others'
]
rgb_chat_color = [
    255,
    255,
    255
]

Example response:

{
    "status": 201,
    "response": "Successfully created group \"Team Penguin\"."
}

Update group

Deprecates: /v2/groups/update
http://127.0.0.1:7878/v3/group/update
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
type = 'id' // Optional; defaults to "name"; options: id, name
name = 24
prefix = '(Team Penguin)'
suffix = null
parent_type = 'id' // Optional; defaults to "name"; options: id, name
parent_group = 23
permissions = [
    'tshock.tp.self',
    'tshock.tp.others'
]
rgb_chat_color = [
    255,
    255,
    255
]

Example response:

{
    "status": 201,
    "response": "Successfully created group \"Team Penguin\"."
}

Delete group

Deprecates: /v2/groups/destroy
http://127.0.0.1:7878/v3/group/delete
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
type = 'id' // Optional; defaults to "name"; options: id, name
group = 24

Example response:

{
    "status": 200,
    "response": "Successfully deleted group \"Team Penguin\"."
}

Users

Registered users info

Relevant: Pryaxis/TShock#901
Deprecates: /v2/users/read
http://127.0.0.1:7878/v3/users
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "response": "Successfully fetched 4 online users.",
    "data": {
        "maximum_allowed": 7,
        "online": [
            {
                "nickname": "Ped",
                "username": "ped",
                "group": "superadmin",
                "team": 0,
                "ip": "127.0.0.1",
                "position": {
                    "longtitude": 3219,
                    "latitude": 290
                },
                "buffs": [
                    {
                        "id": 147,
                        "name": "Banners",
                        "description": [
                            "Increased damage and defense from the following:",
                            "Zombie",
                            "Green Slime"
                        ],
                        "seconds_left": null
                    },
                    {
                        "id": 121,
                        "name": "Fishing",
                        "description": "Increased fishing level",
                        "seconds_left": 480
                    }
                ],
                "inventory": {
                    "items": [
                        {
                            "id": 200,
                            "name": "Green Phaseblade",
                            "description": [
                                "23 melee damage",
                                "9% critical strike chance",
                                "Fast speed",
                                "Weak knockback",
                                "Material",
                                "+5% damage",
                                "+15% knockback"
                            ],
                            "prefix": {
                                "id": 7,
                                "name": "Unpleasant"
                            },
                            "amount": 1
                        },
                        "// x50 elements"
                    ],
                    "coins": [
                        "// Same as items, but without prefix",
                        "// x4 elements"
                    ],
                    "ammo": [
                        "// Same as items, but without prefix",
                        "// x4 elements"
                    ],
                    "trash": null,
                    "holding_item": null,
                    "helmet": {
                        "dye": {
                            "id": 213,
                            "name": "Brown Dye",
                            "description": [
                                "Material"
                            ]
                        },
                        "vanity": {
                            "//": "Same as dye, but with prefix",
                            "prefix": {
                                "id": 7,
                                "name": "Unpleasant"
                            }
                        },
                        "item": {
                            "//": "Same as dye, but with prefix",
                        }
                    },
                    "shirt": {
                        "//": "Same as helmet"
                    },
                    "pants": {
                        "//": "Same as helmet"
                    },
                    "accessories": [
                        {
                            "dye": {
                                "//": "Same as helmet's dye"
                            },
                            "vanity": {
                                "//": "Same as helmet's vanity"
                            },
                            "item": {
                                "//": "Same as dye, but with prefix"
                            }
                        }
                        "// x5 elements"
                    ],
                    "pet": {
                        "dye": {
                            "//": "Same as helmet's dye"
                        },
                        "item": {
                            "//": "Same as helmet's item"
                        }
                    },
                    "light_pet": {
                        "//": "Same as pet"
                    },
                    "mount": {
                        "//": "Same as pet"
                    },
                    "minecart": {
                        "//": "Same as pet"
                    },
                    "grappling_hook": {
                        "//": "Same as pet"
                    }
                }
            },
            "// Other players"
        ]
    }
}

Online info

Relevant: Pryaxis/TShock#901
Deprecates: /v2/server/status, /v2/users/activelist, /v2/players/read, /v2/players/list
http://127.0.0.1:7878/v3/online-users
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'

Example response:

{
    "status": 200,
    "response": "Successfully fetched 4 online users.",
    "data": {
        "maximum_allowed": 7,
        "online": [
            {
                "nickname": "Ped",
                "username": "ped",
                "group": "superadmin",
                "team": 0,
                "ip": "127.0.0.1",
                "position": {
                    "longtitude": 3219,
                    "latitude": 290
                },
                "buffs": [
                    {
                        "id": 147,
                        "name": "Banners",
                        "description": [
                            "Increased damage and defense from the following:",
                            "Zombie",
                            "Green Slime"
                        ],
                        "seconds_left": null
                    },
                    {
                        "id": 121,
                        "name": "Fishing",
                        "description": "Increased fishing level",
                        "seconds_left": 480
                    }
                ],
                "inventory": {
                    "items": [
                        {
                            "id": 200,
                            "name": "Green Phaseblade",
                            "description": [
                                "23 melee damage",
                                "9% critical strike chance",
                                "Fast speed",
                                "Weak knockback",
                                "Material",
                                "+5% damage",
                                "+15% knockback"
                            ],
                            "prefix": {
                                "id": 7,
                                "name": "Unpleasant"
                            },
                            "amount": 1
                        },
                        "// x50 elements"
                    ],
                    "coins": [
                        "// Same as items, but without prefix",
                        "// x4 elements"
                    ],
                    "ammo": [
                        "// Same as items, but without prefix",
                        "// x4 elements"
                    ],
                    "trash": null,
                    "holding_item": null,
                    "helmet": {
                        "dye": {
                            "id": 213,
                            "name": "Brown Dye",
                            "description": [
                                "Material"
                            ]
                        },
                        "vanity": {
                            "//": "Same as dye, but with prefix",
                            "prefix": {
                                "id": 7,
                                "name": "Unpleasant"
                            }
                        },
                        "item": {
                            "//": "Same as dye, but with prefix",
                        }
                    },
                    "shirt": {
                        "//": "Same as helmet"
                    },
                    "pants": {
                        "//": "Same as helmet"
                    },
                    "accessories": [
                        {
                            "dye": {
                                "//": "Same as helmet's dye"
                            },
                            "vanity": {
                                "//": "Same as helmet's vanity"
                            },
                            "item": {
                                "//": "Same as dye, but with prefix"
                            }
                        }
                        "// x5 elements"
                    ],
                    "pet": {
                        "dye": {
                            "//": "Same as helmet's dye"
                        },
                        "item": {
                            "//": "Same as helmet's item"
                        }
                    },
                    "light_pet": {
                        "//": "Same as pet"
                    },
                    "mount": {
                        "//": "Same as pet"
                    },
                    "minecart": {
                        "//": "Same as pet"
                    },
                    "grappling_hook": {
                        "//": "Same as pet"
                    }
                }
            },
            "// Other players"
        ]
    }
}

Create user

Deprecates: /v2/users/create
http://127.0.0.1:7878/v3/user/create
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
username = 'ped'
password = '123123'
group = 'moderator' // Optional; defaults to "default"

Example response:

{
    "status": 201,
    "response": "Successfully created moderator \"ped\"."
}

Update user

Deprecates: /v2/users/update
http://127.0.0.1:7878/v3/user/update
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
type = 'id' // Optional; defaults to "username"; options: id, username
user = 254
// TODO: Add more parameters

Example response:

{
    "status": 200,
    "response": "Successfully updated user 254."
}

Delete user

Deprecates: /v2/users/destroy
http://127.0.0.1:7878/v3/user/delete
data:

token = '5C58D5332D5A51DCC5CFFEBD3813014ECF0248BA104CF12ADE0F93E192E77347'
type = 'id' // Optional; defaults to "username"; options: id, username
user = 254

Example response:

{
    "status": 200,
    "response": "Successfully deleted user from database."
}

Bans

Deprecates: /v2/players/ban

REST API v1 & v2

v1 is out for a very long time. I propose to remove the support to get rid of legacy code. I also propose to deprecate v2 and remove it in August 2018.

Feel free to comment on this. I might have missed something or made some mistakes along the way.

@WhiTexz If v3 is already out, then you can obviously name it v4. I am not aware of v3.

Orion Framework general to-do list

The below contains a list of general items to be completed in the Orion Framework

  • Assembly patcher in OTAPIv2
  • OTAPI v2 Release to NuGet
  • Orion: Project skeleton
  • Orion: Injector framework, Service and plugin bases
  • Orion: Service interface definitions/documentation
  • Orion: Built-in service implementations
    • Service: AAA Service (#31)
    • Service: Command service (#32)
    • Service: Inventory Service
    • Service: REST framework
    • Service: Data/Database service

AAA: Users and Accounts

The general consensus in server applications is that each person connecting is given a User object. This object serves as the main interaction point between the server and the client. Users may register to the system which creates a user Account associated with the user object. Typically, accounts are simply database information that grants the user access to certain features when authenticated to. This issue addresses the nomenclature changes made in a recent commit by defining why we should name our classes in a certain way.

Because Terraria is a game, clients are associated with a Player object which controls how the client interacts with the server. We may call this player object our User. An Orion player is able to authenticate to a user account to be granted access to that account's settings and permissions. In TShock 4, however, we used a User class as a database structure that simply hold information to be stored/retrieved. Users weren't even linked to TSPlayer objects until recently; we'd just store the user id and name on the player object.

Because naming database accounts "User" can be deceiving, and "UserAccount" is an unnecessarily long name for the context, I suggest the following changes to normalize naming in services:

  • Our point of interaction with players remains in the OrionPlayer object and derivatives.
  • IUserAccountService organizes the data accounts and validates authentication to them, so its name should change to simply IAccountService. This makes it fit better alongside IGroupService and IPermissionService as we're not prefixing those with User.
  • Likewise, UserAccount and references should change to simply Account, as we can assume they refer to the accounts used by our players. This partially reverts the latest changes by me taking the opposite approach now that conventions have been made clear to me.

A pull request will be made with proper GitHub Flow guidelines applying these changes. Should this be the nomenclature of choice for our AAA services?
This issue was based on a Slack discussion. Most points have been covered here through a diverse approach.

Hook discovery, and implementation into OTAPI

https://guides.github.com/features/mastering-markdown/

We need a hook matrix of which hooks are featured inside TSAPI and TShock, compared with ones implemented in OTAPI

Hook Catalog

These hooks exist inside TShock and TSAPI as at APIVersion 1.21

Source Name PropertyType In OTAPI
TSAPI GameUpdate typeof(HandlerCollection) [x]
TSAPI GamePostUpdate typeof(HandlerCollection) [x]
TSAPI GameHardmodeTileUpdate typeof(HandlerCollection) [ ]
TSAPI GameInitialize typeof(HandlerCollection) [x]
TSAPI GamePostInitialize typeof(HandlerCollection) [x]
TSAPI GameWorldConnect typeof(HandlerCollection) [ ]
TSAPI GameWorldDisconnect typeof(HandlerCollection) [ ]
TSAPI GameStatueSpawn typeof(HandlerCollection) [x]
TSAPI ItemSetDefaultsInt "typeof(HandlerCollection<SetDefaultsEventArgs<Item,Int32>>)" [x]
TSAPI ItemSetDefaultsString "typeof(HandlerCollection<SetDefaultsEventArgs<Item,String>>)" [x]
TSAPI ItemNetDefaults "typeof(HandlerCollection<SetDefaultsEventArgs<Item,Int32>>)" [x]
TSAPI NetSendData typeof(HandlerCollection) [x]
TSAPI NetGetData typeof(HandlerCollection) [x]
TSAPI NetGreetPlayer typeof(HandlerCollection) [x]
TSAPI NetSendBytes typeof(HandlerCollection) [x]
TSAPI NetNameCollision typeof(HandlerCollection) [x]
TSAPI NpcSetDefaultsInt "typeof(HandlerCollection<SetDefaultsEventArgs<NPC,Int32>>)" [x]
TSAPI NpcSetDefaultsString "typeof(HandlerCollection<SetDefaultsEventArgs<NPC,String>>)" [x]
TSAPI NpcNetDefaults "typeof(HandlerCollection<SetDefaultsEventArgs<NPC,Int32>>)" [x]
TSAPI NpcStrike typeof(HandlerCollection) [x]
TSAPI NpcTransform typeof(HandlerCollection) [x]
TSAPI NpcSpawn typeof(HandlerCollection) [x]
TSAPI NpcLootDrop typeof(HandlerCollection) [x]
TSAPI NpcTriggerPressurePlate typeof(HandlerCollection<TriggerPressurePlateEventArgs>) [x]
TSAPI DropBossBag typeof(HandlerCollection) [x]
TSAPI PlayerUpdatePhysics typeof(HandlerCollection) [ ]
TSAPI PlayerTriggerPressurePlate typeof(HandlerCollection<TriggerPressurePlateEventArgs>) [x]
TSAPI ProjectileSetDefaults "typeof(HandlerCollection<SetDefaultsEventArgs<Projectile,Int32>>)" [x]
TSAPI ProjectileTriggerPressurePlate typeof(HandlerCollection<TriggerPressurePlateEventArgs>) [x]
TSAPI ProjectileAIUpdate typeof(HandlerCollection) [x]
TSAPI ServerCommand typeof(HandlerCollection) [ ]
TSAPI ServerConnect typeof(HandlerCollection) [ ]
TSAPI ServerJoin typeof(HandlerCollection) [ ]
TSAPI ServerLeave typeof(HandlerCollection) [ ]
TSAPI ServerChat typeof(HandlerCollection) [ ]
TSAPI ServerBroadcast typeof(HandlerCollection) [ ]
TSAPI ServerSocketReset typeof(HandlerCollection) [ ]
TSAPI WorldSave typeof(HandlerCollection) [x]
TSAPI WorldStartHardMode typeof(HandlerCollection) [x]
TSAPI WorldMeteorDrop typeof(HandlerCollection) [ ]
TSAPI WorldChristmasCheck typeof(HandlerCollection) [x]
TSAPI WorldHalloweenCheck typeof(HandlerCollection) [x]
TShock AccountCreate typeof(AccountCreateD) n/a
TShock AccountDelete typeof(AccountDeleteD) n/a
TShock ReloadEvent typeof(ReloadEventD) n/a
TShock PlayerPostLogin typeof(PlayerPostLoginD) n/a
TShock PlayerPreLogin typeof(PlayerPreLoginD) n/a
TShock PlayerLogout typeof(PlayerLogoutD) n/a
TShock PlayerCommand typeof(PlayerCommandD) [ ]
TShock PlayerChat typeof(PlayerChatD) [ ]
TShock RegionEntered typeof(RegionEnteredD) n/a
TShock RegionLeft typeof(RegionLeftD) n/a
TShock RegionCreated typeof(RegionCreatedD) n/a
TShock RegionDeleted typeof(RegionDeletedD) n/a

Improve event infrastructure

Our event infrastructure should have the following characteristics:

  • Ensure server QoS. This can be done by adding budgets to event types, and ensuring that we don't go too far over budget when running the event handlers.
  • Asynchronous event handlers. These are event handlers which are run after the synchronous event handlers, and they optionally can be non-blocking, meaning that the event "ends" even before these event handlers are finished running.

Orion v1.4 "Meta" Progress

This issue will serve as a tracker for "meta" Orion progress. Items that fall under this category include, but are not limited to, creating developer-oriented documentation so that other developers can begin contributing to Orion, lobbying for support behind Orion, etc.

  • Clean up the repository. There is a lot of outdated information.
  • Improve the README. This could even just link to the wiki.
  • Clean up and set up labels for issues in this repository.
  • Clean up and set up milestones in this repository.
  • Set up automated documentation generation (#59)
  • Create developer documentation for Orion. That way, we can start onboarding new developers to contribute to Orion. Some areas of contribution include:
    • Defining missing packets.
    • Defining missing modules.
    • Augmenting the current Terraria abstractions (such as adding stats to items, etc.)
  • Write more comprehensive example plugins for Orion. The current example plugin on the wiki sidebar is a start, but we could write something which more explicitly shows the benefits of Orion. We might want to, e.g., provide an example of a service rebinding.
  • Clean up the contributor guidelines for Orion in the wiki.
  • Attempt to rally support behind this.

More items to be added later as needed.

Properly implement IoC

Implement IoC properly, passing around Func<TTerrariaType, OurType>s in order to wrap the necessary objects in, e.g., ItemService, PlayerService, etc.

E.g., Player constructor needs to be something like this:

public Player(Terraria.Player terrariaPlayer, Func<Terraria.Item, Item> itemWrapper, Func<Terraria.Item[], IItemArray> itemArrayWrapper)

Terraria Projectiles

Define and implement IProjectile and IProjectileService abstractions. Implement projectile-related events, as well.

Discussion: Scripting Engine

C# Scripting is now feasibly possible with the Roslyn Compiler Platform. It could be possible to allow for plugins to be loaded in the form of C# source code files and have them dynamically compiled to assemblies at run-time. This could possibly allow for hot-reloading and runtime edits by removing references to the hot-potato code and recompiling it.

This is mentioned by @Patrikkk in #35 during our discussion about plugin hot-reloading. A separate discussion about a scripting engine vs. a pre-compiled plugin engine is worth having. Please funnel all scripting engine discussion to this issue.

Terraria World

Define and implement an abstraction for the Terraria world. Implement world-related events, as well.

POSIX directory structure, packaging support

Proposal - POSIX Directory Structure

The purpose of this proposal is to outline the requirements for server behaviour in regards to POSIX directory structure support and RFC for such features.

Outline

The server should move away from the implicit current directory base structure in favour of a configurable base directory that may be globally based, or overridden to support instances of TShock 5.0 on the same server.

Behaviours

  • Shared modules/plugins should live in the system-wide plugins directory whereas local modules may live in $ORION_BASE_PATH/modules
  • Shared configuration should live in the system-wide configuration directory, and local configuration may live in $ORION_BASE_PATH/config. The path in which configuration resides is transparently handled by the OrionConfiguration module and isn't needed to be worried about by plugins themselves.
  • The server should obey the environment variable ORION_BASE_PATH which specifies an absolute base directory in which to bootstrap itself out of. This method is easily supported by systemd, launchctl and upstart, and allows for one server per host and server instances at the same time
    • In absence of this environment variable (or an ENOENT on the directory specified therein), the server should obey the default system-wide directories.
  • The server should obey the system-wide configuration in all instances, unless overridden by a local configuration file.

Default Directories

GNU/Linux

  • /usr/bin/ - binary directory
  • /etc/orion/ - base system-wide configuration
  • /var/lib/orion - base system-wide orion data
  • /var/lib/orion/modules - base system-wide plugin directory
  • /var/lib/orion/data - base system-wide database directory

MacOSX

  • /usr/bin/ - binary directory
  • /Library/Frameworks/Orion.framework/ - base system-wide orion data
  • /Library/Frameworks/Orion.framework/Modules - base system-wide configuration

Windows

%ProgramFiles%\Orion - base binary directory

Standardize error messages + feedback

I think we should standardize error messages and feedback, like what changed in Pryaxis/TShock@c4cf2d4 with /register in TShock.

I think any error message that gets sent to either the console or a player should have not only a clear message, but a reasonable solution attached too.

Bad:

  1. There was a problem with the database. [StackTrace]
  2. A user already exists by that name.
  3. That group does not exist!

Good:

  1. There was a problem with the database. [StackTrace]. To solve: make sure that your database connection information is correct in the config file, and that the database is running. If you're using MySQL, run netstat -tulpn to verify that MySQL is listening on the port you're trying to connect to.
  2. That user account already exists. Try re-registering with a different username.
  3. The group "adminz" doesn't exist. Did you mean "admins"? If you need to, create a new group with [syntax for new group creation].

In other words, error messages should be both informative and actionable. If the error message is something we can't expect someone to solve, we should make it clear that they need to report the issue on the forums or on Github. Look at what Ruby does if Ruby dies:

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
Don't forget to include the above Crash Report log file.
For details: http://www.ruby-lang.org/bugreport.html

Things to do

Orion Core

  • DI/Module Loader Framework
  • Log4Net
  • Packet repackaging
  • Storage/Database Framework
  • Module configuration Framework
  • Command framework
  • Console Framework

TShock v5

  • Bans
  • SSC
  • User storage
  • Plugin reloading Likely will not happen
  • Database rewrite
  • REST

Logging

What do we want our logger to do?

Feature Request: Wildcard banning.

In the current TShock you cannot ban Wildcard IP's, this is rather annoying as many players have Dynamic IP's.

Example: /ban addw 123.123.123.*

Discussion: Hot plugin loading + reloading

From Slack, #orion-info, there was a discussion with some discrepancy on whether or not plugin hot reloading / reloading would be a part of Orion. According to @ProfessorXz, @MarioE has stated this isn't going to be a feature, but @Enerdy said that the previous reason why we didn't have hotloading in the API was because of issues loading and reloading assemblies. In addition, @Enerdy pointed out that with injection, we should be able to do something similar to this.

So, @MarioE, and everyone in general (cc @NyxStudios/tshock), what's the status on plugin reloading / hot reloading in Orion as far as development targets go?

[RFC] Service framework: SharedService and Service

Up until now there is only support for one type of service, IService which lives in singleton scope. It has been identified that not all services are fit for a singleton, so two service types must be created.

Use Case: Multi-injection

There is no reason for IConfigurationService to be singleton. It would be better served as a generic service that takes a type argument for the class that it is to be serializing, to enable multiples of them to be injected into a target.

Consider the following hypothetical plugin:

public class MyPlugin : OrionPlugin {
    public MyPlugin(Orion orion, IConfigurationService<GlobalConfiguration> globalConfig,
        IConfigurationService<WorldConfiguration> worldConfig) : base(orion)
    {
    }
}

In this example, GlobalConfiguration and WorldConfiguration are classes which hold properties for two different configuration elements in a single plugin, and are best stored in two separate files. Many plugins traditionally use more than one type of configuration so this design is pertinent.

The best use case for non-singleton services would enable the serialization and de-serialization of separate configuration classes, one per service instance. This would require two types of services to be handled by Orion's injection mechanism

Database - [User] structure

Rationale

TShock's current database system for users currently lacks keys and aren't relational. Key identifying credentials such as IP addresses and UUIDs are hacked on in JSON/text columns and aren't useful for a proper SQL relational db.

Many-to-many with [UUID] means that one user may have many UUIDs, and may log in to any account they have been previously bound with by using /login accountname, and UUID reporting becomes very easy, you can now query the database for every [User] that has ever logged in under a specified [UUID].

Many-to-many with [IPAddress] follows the same pattern. It's easy to report on any IP address who has connected to the server, and along with any TShock account they have touched. Conversely, you can report on any IP address who has touched a single TShock account.

Structure

  • [User] Table
    • ID - Primary Key
    • Name - user's account name
    • PasswordHash - self explanatory
    • RegisteredAt - Date account registered
    • LastAccessedAt - Date account was last accessed
    • AllowAccess - Specifically deny access to this account
  • [IPAddress] table
    • ID primary key
    • IPv4Long - long binary representation of IPv4 address - index unique
    • IPv4String - string representation of IPv4 addr
  • [UserHasGroup] joiner table:
    • UserFK Primary Key references [User] cascade
    • GroupFK Primary Key references [Group] cascade
  • [UserHasUUID] joiner table
    • UserFK - Primary Key references [User] cascade
    • UUIDFK - Primary key references [UUID] cascade
  • [UserHasIPAddress] joiner table
    • UserFK primary key references [User] cascade
    • IPAddressFK - Primary key references [IPAddress] cascade

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.