Module: Lich::Gemstone::Infomon::XMLParser
- Defined in:
- documented/gemstone/infomon/xmlparser.rb
Overview
this module handles all of the logic for parsing game lines that infomon depends on
Defined Under Namespace
Modules: Pattern
Class Method Summary collapse
-
.parse(line) ⇒ Symbol
Parses a single line or multi-line block of game server XML output and dispatches to appropriate handlers.
Class Method Details
.parse(line) ⇒ Symbol
Errors are logged to Lich.log and also printed as server responses.
Parses a single line or multi-line block of game server XML output and dispatches to appropriate handlers.
Uses an optimized two-tier strategy: for single-line input or buffered blocks with no embedded newlines, attempts anchored patterns (line-start ^) only at \A and scans just mid-line patterns via AllMidline. For multi-line strings (e.g. buffered combat blocks), falls back to the full union All so inner-line anchors (e.g. NPC death messages) still match. Recognized patterns trigger side effects (NPC status updates, group notifications, container/item roster updates, parser state transitions) and return a status symbol.
Matches trigger:
- Death messages: update NPC status to 'dead'
- Group/arrival: notify Group::Observer, append player nouns to XMLData.arrival_pcs
- Overwatch: delegate to Overwatch::Observer
- STOW/READY output: populate StowList or ReadyList, set "checked" flag
- Status prompt: transition parser state to Parser::State::Ready
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 |
# File 'documented/gemstone/infomon/xmlparser.rb', line 582 def self.parse(line) # Fast path: attempt the anchored union only at line start and scan just # the mid-line patterns. A non-terminal newline means a combined # multi-line string (e.g. buffered combat); fall back to the full union # so inner-line ^ anchors (e.g. death messages) still match. nl = line.index("\n") matched = if nl && nl < line.length - 1 Pattern::All.match?(line) else Pattern::AllStart.match?(line) || Pattern::AllMidline.match?(line) end return :noop unless matched begin case line # this detects for death messages in XML that are not matched with appropriate combat attributes above when Pattern::NpcDeathMessage match = Regexp.last_match if (npc = GameObj.npcs.find { |obj| obj.id == match[:npc_id] && obj.status !~ /\b(?:dead|gone)\b/ }) npc.status = 'dead' end :ok when Pattern::Group_Short return :noop unless (match_data = Group::Observer.wants?(line)) Group::Observer.consume(line.strip, match_data) :ok when Pattern::Overwatch_Short return :noop unless (match_data = Overwatch::Observer.wants?(line)) Overwatch::Observer.consume(line, match_data) :ok when Pattern::Also_Here_Arrival return :noop unless Lich::Claim::Lock.locked? line.scan(%r{<a exist=(?:'|")(?<id>.*?)(?:'|") noun=(?:'|")(?<noun>.*?)(?:'|")>(?<name>.*?)</a>}).each { |player_found| next unless player_found[0].to_s.start_with?('-') next if XMLData.arrival_pcs.include?(player_found[1]) XMLData.arrival_pcs.push(player_found[1]) } :ok when Pattern::StowListOutputStart StowList.reset :ok when Pattern::StowListContainer, Pattern::StowSetContainer1, Pattern::StowSetContainer2 match = Regexp.last_match StowList.__send__("#{match[:type].downcase}=", GameObj.index_or_create(match[:id], match[:noun], match[:name], (match[:before].nil? ? nil : match[:before].strip), (match[:after].nil? ? nil : match[:after].strip))) StowList.checked = true if line =~ Pattern::StowListContainer :ok when Pattern::ReadyListOutputStart ReadyList.reset :ok when Pattern::ReadyListNormal, Pattern::ReadyListAmmo2, Pattern::ReadyListSheathsSet, Pattern::ReadyItemSet match = Regexp.last_match unless match[:id].nil? ReadyList.__send__("#{Lich::Util.normalize_name(match[:type].downcase)}=", GameObj.index_or_create(match[:id], match[:noun], match[:name], (match[:before].nil? ? nil : match[:before].strip), (match[:after].nil? ? nil : match[:after].strip))) end if match.named_captures.include?("store") ReadyList.__send__("store_#{Lich::Util.normalize_name(match[:type].downcase)}=", match[:store]) end :ok when Pattern::ReadyListFinished ReadyList.checked = true :ok when Pattern::ReadyItemClear match = Regexp.last_match ReadyList.__send__("#{Lich::Util.normalize_name(match[:type].downcase)}=", nil) :ok when Pattern::ReadyStoreSet match = Regexp.last_match ReadyList.__send__("store_#{Lich::Util.normalize_name(match[:type].downcase)}=", match[:store]) :ok when Pattern::StatusPrompt Infomon::Parser::State.set(Infomon::Parser::State::Ready) unless Infomon::Parser::State.get.eql?(Infomon::Parser::State::Ready) :ok else :noop end rescue StandardError respond "--- Lich: error: Infomon::XMLParser.parse: #{$!}" respond "--- Lich: error: line: #{line}" Lich.log "error: Infomon::XMLParser.parse: #{$!}\n\t#{$!.backtrace.join("\n\t")}" Lich.log "error: line: #{line}\n\t" end end |