Allen Menschen einen guten Rutsch ins neue Jahr 2019, egal welcher Hautfarbe, Rasse, Zugehörigkeit oder Gesinnung.
Everquest 2 is a bad game run by a bad company
Everquest 2 suffers from neglect and greedy RMT (RMT = real money transactions) micro transactions.
And they’re deleting any honest criticism on their “official” forum.
Additional to that they ban everyone on their “official” discord who even remotely dares say anything about their shit game.
Fallen Gate, the only Premium server, where you have to pay to play, a month into an expansion not even half of the items are adjusted.
Now they’re selling lifetime memberships because they know they won’t last another 3 years.
Their player base has declined by over 40% over 2 years. Even the most diehard people I knew quit playing.
Returning players on live face a RMT wall. You have to buy Krono and sell it to established players so you have a chance of playing with them. How absurd is that?
You need 1060 resolve and about 65k potency in order to function in tier 1 heroic zones.
You can harvest rares for a few days, refine those rares and lose about half in the process, craft armor and jewelry out of those rares and then experiment with that armor and jewelry. This will bring you to about 50k potency.
How the fuck are you supposed to hit 65k potency?
You might think, “craft infusers”. But you don’t have the recipe. It’s behind a daily quest with a RNG (= Random Number Generator) chance to loot it, the chance is little. And when you have it, it only saves you little money because fuel costs too and you spend time acquiring those components by running solo zones to break shit down.
So you’re a returning player, you have about 20k plat. Maybe you’re a long term player and have reached 2×12 year rewards, which will net you 700 loyalty tokens which will net you 700/5*500=70k plat. If you spend them all on loyalty 500p chests.
How long does 70k plat last you? Not long.
Infusing for plat starts at 9p / infusion and the cost is exponential. You can easily burn 300k plat on a single gear piece.
But the biggest problem is the exclusive player base. No matter where you play.
On Fallen Gate there is a guild that wants you to go through a 3 week trial period. In 2018. When the lifetime of one expansion is 3 months.
Other guilds are full or super casual.
Some guilds only group internally.
The fun of eq2 was meeting new people.
This is mostly gone.
And there is RMT everywhere. Don’t want to go through the artificial 1 minute wait to rez your mercenary? Pay real cash.
Research spells quicker? Pay real cash.
What your spells aren’t ancient level yet so the groups won’t take you? You can always buy more virtual currency with real cash.
It’s a game for suckers where the bank always wins.
It’s not even a game anymore but a “game of chance”, like roulette. Only in multitudes.
You can easily see the handwriting of this greedy and neglecting company.
The last SOE expansion was Altar of Malice. It was large and rich with an entertaining story. In the middle of that expansion parts of SOE became Daybreak. First thing they did was sell an extra “content pack” 15 dolla.
Next expansion was the worst expansion ever. ToT – Terrors of Thalumbra. This features the handwriting of “Kander” a mentally unstable child in a man’s body, obsessed with some god complex. It was the base groundwork for “celestial” content there is now. Essentially everything was stripped and only RMT and grind remained.
But hey don’t believe me.
When I returned a received help to get started. 5 pieces of gear. Thanks but I’m afraid it was only a drop of water on a immensely hot stone.
I’m now sitting at 1161.5 resolve but 48k potency. I’m not finding any groups. PQs drop merc trash only. On my 5th day I’m already fed up with it. I want to play with people, but this shit company not only deletes my posts on their official forum, but also put the entry levels too high.
15k extra potency is not attainable without some serious real money or time investment. And with time investment I mean 3 months+.
Some Russian guy was looking for a DPS class, which I play. He was spamming for about an hour. I sent a tell, I didn’t even receive a “sorry we’re full” or anything similar to that.
When the game is shit, and the community is shit and the company running it is shit, what’s left?
update: I got a refund on paper, we’ll see if I receive the money. It takes 5-7 days they wrote.
Angular, EventSource, Go and wasted lifetime
If you have ever used EventSource and Angular and have read all the other blog posts and github issues and Stackoverflow posts and nothing worked, then you’ve probably come here and will happily leave knowing you solved your problem.
First of all I use cobra, I know, get to the point. As part of cobra I add the serve command, so I can go run main.go serve
This is the serve.go file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package cmd import ( "git.icod.de/dalu/eventsrc/server/handler" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/spf13/cobra" ) // serveCmd represents the serve command var serveCmd = &cobra.Command{ Use: "serve", Short: "", Long: ``, RunE: func(cmd *cobra.Command, args []string) error { r := gin.Default() r.Use(cors.Default()) h := handler.NewHandler() defer h.Close() r.GET("/api/v1/events/", h.Stream) return r.Run(":8080") }, } func init() { rootCmd.AddCommand(serveCmd) } |
I set up the route, cors and run it
The server/handler/handler.go file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
package handler import ( "fmt" "log" "time" "github.com/gin-contrib/sse" "github.com/gin-gonic/gin" ) type Handler struct { t *time.Ticker } func NewHandler() *Handler { h := new(Handler) h.t = time.NewTicker(time.Second * 1) return h } func (h *Handler) Close() { h.t.Stop() } func (h *Handler) Stream(cx *gin.Context) { i := 0 w := cx.Writer clientGone := w.CloseNotify() for { select { case <-clientGone: return case t := <-h.t.C: type M struct { Id int `json:"id"` Model string `json:"model"` Action string `json:"action"` Time time.Time `json:"time"` } m := new(M) m.Model = "profile" m.Action = "update" m.Id = 1 m.Time = t h := w.Header() h.Set("Cache-Control", "no-cache") h.Set("Connection", "keep-alive") h.Set("Content-Type", "text/event-stream") h.Set("X-Accel-Buffering", "no") ev := sse.Event{ Id: fmt.Sprintf("%d", i), Event: "message", Data: m, } if e := sse.Encode(w, ev); e != nil { log.Println(e.Error()) return } w.Flush() i++ } } } |
Here is the important part. I wasted the last 6 hours and previous to that 2 days on this issue.
If you’re serving this via nginx, you have to set this header X-Accel-Buffering = no
.
If you don’t send this header responses will get buffered by nginx until the timeout it met then flushed to the client.
The above code has a ticker that ticks every second and sends a new “Server Sent Event”.
Why it didn’t work for me was, as you see above Event: "message"
. I had that set to “darko”.
The Angular service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import {Injectable, NgZone} from '@angular/core'; import {Observable} from 'rxjs'; @Injectable({ providedIn: 'root' }) export class NotiService { constructor(private zone: NgZone) { this.zone = new NgZone({ enableLongStackTrace: false }); } watch(): Observable<object> { return Observable.create((observer) => { const eventSource = new EventSource('/api/v1/events/'); eventSource.onmessage = (event) => this.zone.run(() => { console.log(event); observer.next(JSON.parse(event.data)); }); eventSource.addEventListener('darko', (event: any) => this.zone.run(() =>{ console.log('darko event', event); observer.next(JSON.parse(event.data)); })); eventSource.onerror = error => this.zone.run(() => { if (eventSource.readyState === eventSource.CLOSED) { console.log('The stream has been closed by the server.'); eventSource.close(); observer.complete(); } else { observer.error(error); } }); return () => eventSource.close(); }); } } |
eventSource.onmessage expects a message with the Event: "message"
content. Since I had it set to “darko”,
the onmessage event never fired. If you for whatever reason need to send an event that is not a message type,
the eventSource.addEventListener
is how you listen for that event.
As you might have seen in other blog posts or github issues, zonejs and EventSource aren’t the best of friends.
So you have to wrap it all in zone.run()
so you can have real time updates, and not just when you unsubscribe from the Observable.
Finally, the component
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
import {Component, OnDestroy, OnInit} from '@angular/core'; import {NotiService} from '../noti.service'; @Component({ selector: 'icod-home', templateUrl: './home.component.html', styleUrls: ['./home.component.scss'] }) export class HomeComponent implements OnInit, OnDestroy { msgSub; msgs = []; constructor(private notiService: NotiService) { } ngOnInit() { } ngOnDestroy(): void { if (this.msgSub) { this.msgSub.unsubscribe(); } } watchEvents() { this.msgSub = this.notiService.watch().subscribe( data => { console.log(data); this.msgs.push(data); }); } stopWatching() { this.msgSub.unsubscribe(); } } |
and the component html
1 2 3 4 5 6 |
<button (click)="watchEvents()">Watch Events</button> <button (click)="stopWatching()">Stop Watching</button> <div *ngFor="let msg of msgs"> {{msg|json}} </div> |
Finally, the nginx configuration for the development server. To serve it all.
Here I’m using es.dev.luketic on the local network.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
server { listen 80; listen [::]:80; server_name es.dev.luketic; root /home/darko/WebProjects/es/src; index index.html; error_log /var/log/nginx/es.error; location / { proxy_pass http://localhost:4200; proxy_read_timeout 30; proxy_connect_timeout 30; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } location /sockjs-node/ { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; rewrite ^/(.*)$ /$1 break; proxy_set_header Host localhost; proxy_pass http://localhost:4200/; } location ~ ^/api/v1/.* { proxy_pass http://localhost:8080; proxy_read_timeout 30; proxy_connect_timeout 30; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } |